mirror of
https://github.com/gryf/wmdocklib.git
synced 2025-12-19 12:28:10 +01:00
committed initial version. don't look at the time-stamp: these files are
dated back in 2003 or so.
This commit is contained in:
8
pywmdatetime/INSTALL
Normal file
8
pywmdatetime/INSTALL
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
1. If you don't have pywmgeneral installed, install it first. Can be found
|
||||||
|
at http://foo.unix.se/pywmdockapps
|
||||||
|
|
||||||
|
2. Copy pywmdatetime.py to somewhere in your path (like ~/bin or
|
||||||
|
/usr/local/bin).
|
||||||
|
|
||||||
|
3. Copy the sample.pywmdatetimerc to ~/.pywmdatetimerc and edit as you like.
|
||||||
|
|
||||||
15
pywmdatetime/README
Normal file
15
pywmdatetime/README
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[WHAT]
|
||||||
|
Pywmdatetime is a WindowMaker dockapp for displaying time, date and
|
||||||
|
some other information. The colors and formats are easy to configure
|
||||||
|
through the configuration file or as command line arguments. Invoke
|
||||||
|
the program with --help or see the sample rc-file for more information.
|
||||||
|
|
||||||
|
[WHY]
|
||||||
|
I made it mostly because there was no time displaying app that suited my
|
||||||
|
needs. I also made it to try out my newly written Python module for that
|
||||||
|
provides helping functions for making dockapps.
|
||||||
|
|
||||||
|
[CONTACT]
|
||||||
|
Mail anything related to this program to me, Kristoffer Erlandsson,
|
||||||
|
<krier115@student.liu.se>
|
||||||
|
|
||||||
346
pywmdatetime/pywmdatetime.py
Executable file
346
pywmdatetime/pywmdatetime.py
Executable file
@@ -0,0 +1,346 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
'''pywmdatetime.py
|
||||||
|
|
||||||
|
WindowMaker dockapp that displays time, date, weekday and week number.
|
||||||
|
|
||||||
|
Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
|
||||||
|
Licensed under the GNU General Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
2003-06-24 Kristoffer Erlandsson
|
||||||
|
Added event handling for graceful shutdown
|
||||||
|
|
||||||
|
2003-06-16 Kristoffer Erlandsson
|
||||||
|
First workingish version
|
||||||
|
|
||||||
|
'''
|
||||||
|
usage = '''pywmdatetime.py [options]
|
||||||
|
Available options are:
|
||||||
|
-h, --help print this help
|
||||||
|
-f, --foreground <color> set the foreground color
|
||||||
|
-b, --background <color> set the background color
|
||||||
|
-t, --timeformat <format> set the time format
|
||||||
|
-d, --dateformat <format> set the date format
|
||||||
|
-y, --weekdayformat <format> set the weekday format
|
||||||
|
-e, --weekformat <format> set the week format
|
||||||
|
-r, --rgbfile <file> set the rgb file to get color codes from
|
||||||
|
-c, --configfile <file> set the config file to use
|
||||||
|
|
||||||
|
The formats are the same as Python's strftime() accept. See the sample
|
||||||
|
rc-file for more information about this.
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pywmhelpers
|
||||||
|
|
||||||
|
width = 64
|
||||||
|
height = 64
|
||||||
|
|
||||||
|
lettersStartX = 0
|
||||||
|
lettersStartY = 74
|
||||||
|
letterWidth = 6
|
||||||
|
letterHeight = 8
|
||||||
|
|
||||||
|
digitsStartX = 0
|
||||||
|
digitsStartY = 64
|
||||||
|
digitWidth = 6
|
||||||
|
digitHeight = 8
|
||||||
|
|
||||||
|
xOffset = 4
|
||||||
|
yOffset = 4
|
||||||
|
|
||||||
|
letters = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
|
digits = '0123456789:/- '
|
||||||
|
|
||||||
|
timeDefaultFormat = '%H:%M:%S'
|
||||||
|
dateDefaultFormat = '%d-%m-%y'
|
||||||
|
dayDefaultFormat = '%A'
|
||||||
|
weekDefaultFormat = 'wk %q' # %q added by me for different week calculation.
|
||||||
|
|
||||||
|
defaultConfigFile = '~/.pywmdatetimerc'
|
||||||
|
defaultRGBFiles = ['/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt']
|
||||||
|
maxCharsPerLine = 9
|
||||||
|
|
||||||
|
def addString(s, x, y):
|
||||||
|
try:
|
||||||
|
pywmhelpers.addString(s, x, y, letterWidth, letterHeight, lettersStartX,
|
||||||
|
lettersStartY, letters, digitWidth, digitHeight,
|
||||||
|
digitsStartX, digitsStartY, digits, xOffset, yOffset,
|
||||||
|
width, height)
|
||||||
|
except ValueError, e:
|
||||||
|
sys.stderr.write('Error when painting string:\n' + str(e) + '\n')
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
def getCenterStartPos(s):
|
||||||
|
return pywmhelpers.getCenterStartPos(s, letterWidth, width, xOffset)
|
||||||
|
|
||||||
|
def getVertSpacing(numLines, margin):
|
||||||
|
return pywmhelpers.getVertSpacing(numLines, margin, height, letterHeight,
|
||||||
|
yOffset)
|
||||||
|
|
||||||
|
def calculateWeek(localTime):
|
||||||
|
'''Calculate the week number as we do, for example in Sweden.
|
||||||
|
|
||||||
|
That is, add one to the %W format if the year didn't start on a monday.'''
|
||||||
|
day = int(time.strftime('%j', localTime))
|
||||||
|
weekDay = int(time.strftime('%w')) - 1
|
||||||
|
if weekDay == -1:
|
||||||
|
weekDay = 6
|
||||||
|
lastMonday = day - weekDay
|
||||||
|
if lastMonday % 7 == 0:
|
||||||
|
return int(time.strftime('%W'))
|
||||||
|
return int(time.strftime('%W')) + 1
|
||||||
|
|
||||||
|
def parseCommandLine(argv):
|
||||||
|
'''Parse the commandline. Return a dictionary with options and values.'''
|
||||||
|
shorts = 'hf:b:t:d:e:y:r:c:'
|
||||||
|
longs = ['help', 'foreground=', 'background=', 'timeformat=', 'dateformat=',
|
||||||
|
'weekdayformat=', 'weekformat=', 'rgbfile=', 'configfile=']
|
||||||
|
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 ('-f', '--foreground'):
|
||||||
|
d['foreground'] = a
|
||||||
|
if o in ('-b', '--background'):
|
||||||
|
d['background'] = a
|
||||||
|
if o in ('-t', '--timeformat'):
|
||||||
|
d['timeformat'] = a
|
||||||
|
if o in ('-d', '--dateformat'):
|
||||||
|
d['dateformat'] = a
|
||||||
|
if o in ('-y', '--weekdayformat'):
|
||||||
|
d['weekdayformat'] = a
|
||||||
|
if o in ('-e', '--weekformat'):
|
||||||
|
d['weekformat'] = a
|
||||||
|
if o in ('-r', '--rgbfile'):
|
||||||
|
d['rgbfile'] = a
|
||||||
|
if o in ('-c', '--configfile'):
|
||||||
|
d['configfile'] = a
|
||||||
|
return d
|
||||||
|
|
||||||
|
def checkForEvents():
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
while not event is None:
|
||||||
|
if event['type'] == 'destroynotify':
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def mainLoop(timeFmt, dateFmt, dayFmt, weekFmt):
|
||||||
|
recalcWeek = weekFmt.find('%q') + 1 # True if we found %q.
|
||||||
|
counter = -1
|
||||||
|
while 1:
|
||||||
|
counter += 1
|
||||||
|
checkForEvents()
|
||||||
|
lt = time.localtime()
|
||||||
|
timeStr = time.strftime(timeFmt, lt)[:maxCharsPerLine]
|
||||||
|
margin = 3
|
||||||
|
spacing = getVertSpacing(4, margin)
|
||||||
|
timeX = getCenterStartPos(timeStr)
|
||||||
|
addString(timeStr, timeX, margin)
|
||||||
|
if counter % 100 == 0:
|
||||||
|
# We only perform the date/week checks/updates once every 100th
|
||||||
|
# iteration. We will maybe lag behind a couple of seconds when
|
||||||
|
# switching, but switching occurs seldom and it will be alot of
|
||||||
|
# unnecessary checks :).
|
||||||
|
dateStr = time.strftime(dateFmt, lt)[:maxCharsPerLine]
|
||||||
|
if recalcWeek:
|
||||||
|
week = calculateWeek(lt)
|
||||||
|
weekFmt = weekFmt.replace('%q', str(week))
|
||||||
|
weekStr = time.strftime(weekFmt, lt)[:maxCharsPerLine]
|
||||||
|
dayStr = time.strftime(dayFmt, lt)[:maxCharsPerLine]
|
||||||
|
|
||||||
|
dateX = getCenterStartPos(dateStr)
|
||||||
|
weekX = getCenterStartPos(weekStr)
|
||||||
|
dayX = getCenterStartPos(dayStr)
|
||||||
|
addString(dateStr, dateX, margin + spacing + letterWidth)
|
||||||
|
addString(dayStr, dayX, margin + 2 * (spacing + letterWidth))
|
||||||
|
addString(weekStr, weekX, margin + 3 * (spacing + letterWidth))
|
||||||
|
counter = 0
|
||||||
|
pywmhelpers.redraw()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
def parseColors(defaultRGBFileNames, config, xpm):
|
||||||
|
rgbFileName = ''
|
||||||
|
for fn in defaultRGBFileNames:
|
||||||
|
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 (<config_key>, <xpm-key>) pairs.
|
||||||
|
colors = (('foreground', 'text'),
|
||||||
|
('background', 'background'))
|
||||||
|
for key, value in colors:
|
||||||
|
col = config.get(key)
|
||||||
|
if not col is None:
|
||||||
|
code = pywmhelpers.getColorCode(col, rgbFileName)
|
||||||
|
if code is None:
|
||||||
|
sys.stderr.write('Bad colorcode for %s, ignoring.\n' % key)
|
||||||
|
else:
|
||||||
|
pywmhelpers.setColor(xpm, value, code)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
clConfig = parseCommandLine(sys.argv)
|
||||||
|
configFile = clConfig.get('configfile', defaultConfigFile)
|
||||||
|
configFile = os.path.expanduser(configFile)
|
||||||
|
fileConfig = pywmhelpers.readConfigFile(configFile, sys.stderr)
|
||||||
|
# Merge the two configs, let the commandline options overwrite those in the
|
||||||
|
# configuration file.
|
||||||
|
config = fileConfig
|
||||||
|
for i in clConfig.iteritems():
|
||||||
|
config[i[0]] = i[1]
|
||||||
|
|
||||||
|
parseColors(defaultRGBFiles, config, xpm)
|
||||||
|
pywmhelpers.setDefaultPixmap(xpm)
|
||||||
|
timeFmt = config.get('timeformat', timeDefaultFormat)
|
||||||
|
dateFmt = config.get('dateformat', dateDefaultFormat)
|
||||||
|
dayFmt = config.get('weekdayformat', dayDefaultFormat)
|
||||||
|
weekFmt = config.get('weekformat', weekDefaultFormat)
|
||||||
|
# openXwindow sets the window title to the program name. If we get the
|
||||||
|
# program name with a path, split it so we only name the window with the
|
||||||
|
# filename.
|
||||||
|
try:
|
||||||
|
programName = sys.argv[0].split(os.sep)[-1]
|
||||||
|
except IndexError: # Should only happen when using the interpreter.
|
||||||
|
programName = ''
|
||||||
|
sys.argv[0] = programName
|
||||||
|
pywmhelpers.openXwindow(sys.argv, width, height)
|
||||||
|
mainLoop(timeFmt, dateFmt, dayFmt, weekFmt)
|
||||||
|
|
||||||
|
xpm = \
|
||||||
|
['160 100 11 1',
|
||||||
|
' \tc #208120812081',
|
||||||
|
'.\tc #00000000FFFF',
|
||||||
|
'o\tc #C71BC30BC71B',
|
||||||
|
'O\tc #861782078E38',
|
||||||
|
'+\tc #EFBEF3CEEFBE',
|
||||||
|
'@\tc #618561856185',
|
||||||
|
'#\tc #9E79A2899E79',
|
||||||
|
'$\tc #410341034103',
|
||||||
|
'/\tc #2020b2b2aaaa s graph',
|
||||||
|
'X\tc #000000000000 s background',
|
||||||
|
'%\tc #2081B2CAAEBA s text',
|
||||||
|
' ................................................................................................',
|
||||||
|
' ..///...........................................................................................',
|
||||||
|
' ..///...........................................................................................',
|
||||||
|
' ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ..///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' ..///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' ................................................................................................',
|
||||||
|
' ................................................................................................',
|
||||||
|
' ................................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XXX%XXX%%%%%X%%%%%X%XXX%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%XXXXXXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XX%%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%%%%%XX%%%%X%%%%%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXXXXXX%XXX%%%%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XX%%XXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XX%%%XX%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XX%%XXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'XX%%%XX%%%%XXX%%%%X%%%%XX%%%%XX%%%%%X%%%%%X%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%XXX%X%%%%XX%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%%%%%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%%X%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%X%XXX%X%XXX%XXXXX%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%X%X%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%XX%X%XX%XXX%XXXX%XXXXX',
|
||||||
|
'X%%%%%X%%%%XX%XXXXX%XXX%X%%%%XX%%%%XX%X%%%X%%%%%XXX%XXXXXXX%X%%%XXX%XXXXX%XXX%X%XXX%X%XXX%X%%%%%X%%XX%X%%%%XX%%%%%XXX%XXX%XXX%X%XXX%X%XXX%XXX%XXX%%%%%XXX%XXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%X%X%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%X%X%XX%X%XXXXXX%XX%XXXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXX%XXX%X%XXX%X%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%XX%%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%%X%%X%XXX%XXXXX%X%XXXXXXXX',
|
||||||
|
'X%XXX%X%%%%XXX%%%%X%%%%XX%%%%XX%XXXXX%%%%%X%XXX%XXX%XXXX%%%XX%XXX%X%%%%XX%XXX%X%XXX%X%%%%%X%XXXXX%%%%%X%XXX%X%%%%%XXX%XXXX%%%%XX%%%XX%XXX%X%XXX%X%%%%%X%%%%%XXXX',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................']
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
42
pywmdatetime/sample.pywmdatetimerc
Normal file
42
pywmdatetime/sample.pywmdatetimerc
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
# The formats are the same as Python's strftime accept, but one format is
|
||||||
|
# added. %q now means the week-number with monday as the start of the week and
|
||||||
|
# the first day of the year is allways in week 1. We calculate like that for
|
||||||
|
# example here in Sweden.
|
||||||
|
#
|
||||||
|
# Taken from the Python manual:
|
||||||
|
# %a Locale's abbreviated weekday name.
|
||||||
|
# %A Locale's full weekday name.
|
||||||
|
# %b Locale's abbreviated month name.
|
||||||
|
# %B Locale's full month name.
|
||||||
|
# %c Locale's appropriate date and time representation.
|
||||||
|
# %d Day of the month as a decimal number [01,31].
|
||||||
|
# %H Hour (24-hour clock) as a decimal number [00,23].
|
||||||
|
# %I Hour (12-hour clock) as a decimal number [01,12].
|
||||||
|
# %j Day of the year as a decimal number [001,366].
|
||||||
|
# %m Month as a decimal number [01,12].
|
||||||
|
# %M Minute as a decimal number [00,59].
|
||||||
|
# %p Locale's equivalent of either AM or PM.
|
||||||
|
# %S Second as a decimal number [00,61].
|
||||||
|
# %U Week number of the year (Sunday as the first day of the week) as a
|
||||||
|
# decimal number [00,53]. All days in a new year preceding the first
|
||||||
|
# Sunday are considered to be in week 0.
|
||||||
|
# %w Weekday as a decimal number [0(Sunday),6].
|
||||||
|
# %W Week number of the year (Monday as the first day of the week) as a
|
||||||
|
# decimal number [00,53]. All days in a new year preceding the first
|
||||||
|
# Monday are considered to be in week 0.
|
||||||
|
# %x Locale's appropriate date representation.
|
||||||
|
# %X Locale's appropriate time representation.
|
||||||
|
# %y Year without century as a decimal number [00,99].
|
||||||
|
# %Y Year with century as a decimal number.
|
||||||
|
# %Z Time zone name (or by no characters if no time zone exists).
|
||||||
|
# %% A literal "%" character.
|
||||||
|
|
||||||
|
background=black
|
||||||
|
foreground=light sea green
|
||||||
|
timeformat=%H:%M:%S
|
||||||
|
dateformat=%d-%m-%y
|
||||||
|
weekdayformat=%A
|
||||||
|
weekformat=wk %q
|
||||||
|
#rgbfile=/usr/lib/X11/rgb.txt
|
||||||
|
|
||||||
10
pywmgeneral/INSTALL
Normal file
10
pywmgeneral/INSTALL
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
1. Edit setup.py and make XLibDir point to the directory containing the
|
||||||
|
X shared libraries and make XIncludes point to the directory
|
||||||
|
containing your X includes.
|
||||||
|
|
||||||
|
2. Su root.
|
||||||
|
|
||||||
|
3. run './setup.py install'
|
||||||
|
|
||||||
|
Now the library should be built and installed as an Python extension module.
|
||||||
|
|
||||||
10
pywmgeneral/PKG-INFO
Normal file
10
pywmgeneral/PKG-INFO
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: pywmgeneral
|
||||||
|
Version: 0.1
|
||||||
|
Summary: Python module for making WindowMaker dockapps.
|
||||||
|
Home-page: http://foo.unix.se/pywmdockapps
|
||||||
|
Author: Kristoffer Erlandsson
|
||||||
|
Author-email: krier115@student.liu.se
|
||||||
|
License: GPL
|
||||||
|
Description: UNKNOWN
|
||||||
|
Platform: UNKNOWN
|
||||||
23
pywmgeneral/README
Normal file
23
pywmgeneral/README
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[WHAT]
|
||||||
|
Pywmgeneral is a python module that will help you develope WindowMaker
|
||||||
|
dockapps in python. It is mostly a wrapper around the functions from the
|
||||||
|
popular wmgeneral.c, but some new functions are added too.
|
||||||
|
|
||||||
|
It also contains the Python written module pywmhelpers.py which contains
|
||||||
|
functions to aid the development of wm dockapps. This module contains python
|
||||||
|
functions that wrap up the functions which the extension module provides.
|
||||||
|
They ease up argument passing and give nicer return values. Some additional
|
||||||
|
functions, like help for handling a simple configuration file is also
|
||||||
|
available. This module is better documented than the pywmgeneral. It is
|
||||||
|
adviced to only use pywmhelpers and not touch the pywmgeneral module
|
||||||
|
directly at all. For information about how to use the module, see the
|
||||||
|
documentation in pywmhelpers.py. It is also possible to import it in the
|
||||||
|
interactive interpreter and issue 'help(pywmhelpers)'.
|
||||||
|
|
||||||
|
[INSTALLATION]
|
||||||
|
See the file INSTALL
|
||||||
|
|
||||||
|
[CONTACT]
|
||||||
|
Anything related to this piece of software can be e-mailed to me, Kristoffer
|
||||||
|
Erlandsson, <krier115@student.liu.se>.
|
||||||
|
|
||||||
596
pywmgeneral/pywmgeneral.c
Normal file
596
pywmgeneral/pywmgeneral.c
Normal file
@@ -0,0 +1,596 @@
|
|||||||
|
/* pywmgeneral.c
|
||||||
|
*
|
||||||
|
* Python bindings to some of the most important functions in the widely used
|
||||||
|
* wmgeneral.c. Also some added functions. The rc file parser is removed since
|
||||||
|
* Python provide better facilities for this.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License.
|
||||||
|
*
|
||||||
|
* History:
|
||||||
|
*
|
||||||
|
* 2003-06-24 Kristoffer Erlandsson
|
||||||
|
* Added some additional event handling.
|
||||||
|
*
|
||||||
|
* 2003-06-16 Kristoffer Erlandsson
|
||||||
|
* Added checkForMouseClick to make catching of mouse clicks available from
|
||||||
|
* Python.
|
||||||
|
*
|
||||||
|
* 2003-06-14 Kristoffer Erlandsson
|
||||||
|
* Finished support for "everything" included in wmgeneral by default.
|
||||||
|
*
|
||||||
|
* 2003-06-13 Kristoffer Erlandsson
|
||||||
|
* File created made most of the pure wrapper functions and xpm inclusion.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Thanks to Martijn Pieterse for createing the original wmgeneral.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/xpm.h>
|
||||||
|
#include <X11/extensions/shape.h>
|
||||||
|
|
||||||
|
#include "pywmgeneral.h"
|
||||||
|
|
||||||
|
/*****************/
|
||||||
|
/* X11 Variables */
|
||||||
|
/*****************/
|
||||||
|
|
||||||
|
Window Root;
|
||||||
|
int screen;
|
||||||
|
int x_fd;
|
||||||
|
int d_depth;
|
||||||
|
XSizeHints mysizehints;
|
||||||
|
XWMHints mywmhints;
|
||||||
|
Pixel back_pix, fore_pix;
|
||||||
|
char *Geometry = "";
|
||||||
|
Window iconwin, win;
|
||||||
|
GC NormalGC;
|
||||||
|
XpmIcon wmgen;
|
||||||
|
Pixmap pixmask;
|
||||||
|
Atom deleteAtom; /* Added 2003-06-24 for graceful shutdown. */
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* The Python stuff */
|
||||||
|
/*****************************************************************************/
|
||||||
|
static char **pixmap; /* Global pixmap, we only support one of these */
|
||||||
|
static char *maskBits; /* Global maskbits, also only 1 supported */
|
||||||
|
|
||||||
|
char **pyListToStrs(PyObject *l) {
|
||||||
|
/* Convert a python list of strings to a char **. */
|
||||||
|
int size, i;
|
||||||
|
char **target;
|
||||||
|
PyObject *s;
|
||||||
|
if (!PyList_Check(l)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "List expected.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size = PyList_Size(l);
|
||||||
|
target = (char **)malloc(size * sizeof(char *));
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
s = PySequence_GetItem(l, i);
|
||||||
|
if (s == NULL)
|
||||||
|
return NULL; /* Shouldn't happen. */
|
||||||
|
if (!PyString_Check(s)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "String expected.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
target[i] = PyString_AsString(s);
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_includePixmap(PyObject *self, PyObject *args) {
|
||||||
|
/* Set the global pixmap. */
|
||||||
|
PyObject *arg;
|
||||||
|
if (!PyArg_ParseTuple(args, "O", &arg))
|
||||||
|
return NULL;
|
||||||
|
if(!(pixmap = pyListToStrs(arg)))
|
||||||
|
return NULL;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_openXwindow(PyObject *self, PyObject *args) {
|
||||||
|
/* This function now uses the global variable pixmap as xpm and creates the
|
||||||
|
* xbm mask of the given height and width from this one. IOW no other xbm
|
||||||
|
* masks are supported at the moment. This shouldn't be needed except in
|
||||||
|
* special cases (I think...)
|
||||||
|
*/
|
||||||
|
int argc, width, height;
|
||||||
|
PyObject *argvTmp;
|
||||||
|
char **argv;
|
||||||
|
if (!PyArg_ParseTuple(args, "iOii", &argc, &argvTmp, &width, &height))
|
||||||
|
return NULL;
|
||||||
|
if (!(argv = pyListToStrs(argvTmp)))
|
||||||
|
return NULL;
|
||||||
|
maskBits = (char *)malloc(width * height * sizeof(char));
|
||||||
|
createXBMfromXPM(maskBits, pixmap, width, height);
|
||||||
|
openXwindow(argc, argv, pixmap, maskBits, width, height);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_redrawWindow(PyObject *self, PyObject *args) {
|
||||||
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
return NULL;
|
||||||
|
RedrawWindow();
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_redrawWindowXY(PyObject *self, PyObject *args) {
|
||||||
|
int x, y;
|
||||||
|
if (!PyArg_ParseTuple(args, "ii", &x, &y))
|
||||||
|
return NULL;
|
||||||
|
RedrawWindowXY(x, y);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_addMouseRegion(PyObject *self, PyObject *args) {
|
||||||
|
int index, left, top, right, bottom;
|
||||||
|
if (!PyArg_ParseTuple(args, "iiiii", &index, &left, &top, &right, &bottom))
|
||||||
|
return NULL;
|
||||||
|
AddMouseRegion(index, left, top, right, bottom);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_checkMouseRegion(PyObject *self, PyObject *args) {
|
||||||
|
int x, y;
|
||||||
|
if (!PyArg_ParseTuple(args, "ii", &x, &y))
|
||||||
|
return NULL;
|
||||||
|
return Py_BuildValue("i", CheckMouseRegion(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_copyXPMArea(PyObject *self, PyObject *args) {
|
||||||
|
/* x - source x, y - source y
|
||||||
|
* sx - width, sy - height
|
||||||
|
* dx - destination x, dy - destination y
|
||||||
|
*
|
||||||
|
* Variables named as in the original wmgeneral.c, don't blame me for it :)
|
||||||
|
*/
|
||||||
|
int x, y, sx, sy, dx, dy;
|
||||||
|
if (!PyArg_ParseTuple(args, "iiiiii", &x, &y, &sx, &sy, &dx, &dy))
|
||||||
|
return NULL;
|
||||||
|
copyXPMArea(x, y, sx, sy, dx, dy);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pywmgeneral_checkForEvents(PyObject *self, PyObject *args) {
|
||||||
|
/* If we find an event we handle, return a dicitionary containing some
|
||||||
|
* information about it. Return None if there are no events we handle.
|
||||||
|
* Ignore events we don't handle. Also we provide a handler for when the
|
||||||
|
* window is exposed, redraw it.
|
||||||
|
*/
|
||||||
|
XEvent event;
|
||||||
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
return NULL;
|
||||||
|
while (XPending(display)) {
|
||||||
|
XNextEvent(display, &event);
|
||||||
|
if (event.type == Expose) {
|
||||||
|
RedrawWindow();
|
||||||
|
}
|
||||||
|
else if (event.type == ClientMessage) {
|
||||||
|
if((Atom)event.xclient.data.l[0] == deleteAtom) {
|
||||||
|
XCloseDisplay(display);
|
||||||
|
return Py_BuildValue("{s:s}", "type", "destroynotify");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event.type == DestroyNotify) {
|
||||||
|
/* This seems to never happen, why? */
|
||||||
|
XCloseDisplay(display);
|
||||||
|
return Py_BuildValue("{s:s}", "type", "destroynotify");
|
||||||
|
}
|
||||||
|
else if (event.type == ButtonRelease) {
|
||||||
|
return Py_BuildValue("{s:s,s:i,s:i,s:i}", "type", "buttonrelease",
|
||||||
|
"button", event.xbutton.button, "x",
|
||||||
|
event.xbutton.x, "y", event.xbutton.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef PyWmgeneralMethods[] = {
|
||||||
|
{"openXwindow", pywmgeneral_openXwindow, METH_VARARGS,
|
||||||
|
"Open the X window containing everything."},
|
||||||
|
{"includePixmap", pywmgeneral_includePixmap, METH_VARARGS,
|
||||||
|
"Set the global pixmap that will be used as a mask and for everything else."},
|
||||||
|
{"redrawWindow", pywmgeneral_redrawWindow, METH_VARARGS,
|
||||||
|
"Redraw the window."},
|
||||||
|
{"redrawWindowXY", pywmgeneral_redrawWindowXY, METH_VARARGS,
|
||||||
|
"Redraw a give region of the window."},
|
||||||
|
{"addMouseRegion", pywmgeneral_addMouseRegion, METH_VARARGS,
|
||||||
|
"Add a mouse region with a given index."},
|
||||||
|
{"checkMouseRegion", pywmgeneral_checkMouseRegion, METH_VARARGS,
|
||||||
|
"Check if the given coordinates are in any mouse region."},
|
||||||
|
{"copyXPMArea", pywmgeneral_copyXPMArea, METH_VARARGS,
|
||||||
|
"Copy an area of the global XPM."},
|
||||||
|
{"checkForEvents", pywmgeneral_checkForEvents, METH_VARARGS,
|
||||||
|
"Check for some Xevents"},
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
void initpywmgeneral(void) {
|
||||||
|
Py_InitModule("pywmgeneral", PyWmgeneralMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Original C sources (With some modifications) */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************/
|
||||||
|
/* Mouse Regions */
|
||||||
|
/*****************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int enable;
|
||||||
|
int top;
|
||||||
|
int bottom;
|
||||||
|
int left;
|
||||||
|
int right;
|
||||||
|
} MOUSE_REGION;
|
||||||
|
|
||||||
|
MOUSE_REGION mouse_region[MAX_MOUSE_REGION];
|
||||||
|
|
||||||
|
/***********************/
|
||||||
|
/* Function Prototypes */
|
||||||
|
/***********************/
|
||||||
|
|
||||||
|
static void GetXPM(XpmIcon *, char **);
|
||||||
|
static Pixel GetColor(char *);
|
||||||
|
void RedrawWindow(void);
|
||||||
|
void AddMouseRegion(int, int, int, int, int);
|
||||||
|
int CheckMouseRegion(int, int);
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* GetXPM *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
static void GetXPM(XpmIcon *wmgen, char *pixmap_bytes[]) {
|
||||||
|
|
||||||
|
XWindowAttributes attributes;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* For the colormap */
|
||||||
|
XGetWindowAttributes(display, Root, &attributes);
|
||||||
|
|
||||||
|
wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
|
||||||
|
|
||||||
|
err = XpmCreatePixmapFromData(display, Root, pixmap_bytes, &(wmgen->pixmap),
|
||||||
|
&(wmgen->mask), &(wmgen->attributes));
|
||||||
|
|
||||||
|
if (err != XpmSuccess) {
|
||||||
|
fprintf(stderr, "Not enough free colorcells.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* GetColor *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
static Pixel GetColor(char *name) {
|
||||||
|
|
||||||
|
XColor color;
|
||||||
|
XWindowAttributes attributes;
|
||||||
|
|
||||||
|
XGetWindowAttributes(display, Root, &attributes);
|
||||||
|
|
||||||
|
color.pixel = 0;
|
||||||
|
if (!XParseColor(display, attributes.colormap, name, &color)) {
|
||||||
|
fprintf(stderr, "wm.app: can't parse %s.\n", name);
|
||||||
|
} else if (!XAllocColor(display, attributes.colormap, &color)) {
|
||||||
|
fprintf(stderr, "wm.app: can't allocate %s.\n", name);
|
||||||
|
}
|
||||||
|
return color.pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* flush_expose *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
static int flush_expose(Window w) {
|
||||||
|
|
||||||
|
XEvent dummy;
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* RedrawWindow *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
void RedrawWindow(void) {
|
||||||
|
|
||||||
|
flush_expose(iconwin);
|
||||||
|
XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
|
||||||
|
0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||||
|
flush_expose(win);
|
||||||
|
XCopyArea(display, wmgen.pixmap, win, NormalGC,
|
||||||
|
0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* RedrawWindowXY *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
void RedrawWindowXY(int x, int y) {
|
||||||
|
|
||||||
|
flush_expose(iconwin);
|
||||||
|
XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
|
||||||
|
x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||||
|
flush_expose(win);
|
||||||
|
XCopyArea(display, wmgen.pixmap, win, NormalGC,
|
||||||
|
x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* AddMouseRegion *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
void AddMouseRegion(int index, int left, int top, int right, int bottom) {
|
||||||
|
|
||||||
|
if (index < MAX_MOUSE_REGION) {
|
||||||
|
mouse_region[index].enable = 1;
|
||||||
|
mouse_region[index].top = top;
|
||||||
|
mouse_region[index].left = left;
|
||||||
|
mouse_region[index].bottom = bottom;
|
||||||
|
mouse_region[index].right = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* CheckMouseRegion *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
int CheckMouseRegion(int x, int y) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
|
||||||
|
for (i=0; i<MAX_MOUSE_REGION && !found; i++) {
|
||||||
|
if (mouse_region[i].enable &&
|
||||||
|
x <= mouse_region[i].right &&
|
||||||
|
x >= mouse_region[i].left &&
|
||||||
|
y <= mouse_region[i].bottom &&
|
||||||
|
y >= mouse_region[i].top)
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
if (!found) return -1;
|
||||||
|
return (i-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* createXBMfromXPM *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
void createXBMfromXPM(char *xbm, char **xpm, int sx, int sy) {
|
||||||
|
|
||||||
|
int i,j,k;
|
||||||
|
int width, height, numcol, depth;
|
||||||
|
int zero=0;
|
||||||
|
unsigned char bwrite;
|
||||||
|
int bcount;
|
||||||
|
int curpixel;
|
||||||
|
|
||||||
|
sscanf(*xpm, "%d %d %d %d", &width, &height, &numcol, &depth);
|
||||||
|
|
||||||
|
|
||||||
|
for (k=0; k!=depth; k++)
|
||||||
|
{
|
||||||
|
zero <<=8;
|
||||||
|
zero |= xpm[1][k];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=numcol+1; i < numcol+sy+1; i++) {
|
||||||
|
bcount = 0;
|
||||||
|
bwrite = 0;
|
||||||
|
for (j=0; j<sx*depth; j+=depth) {
|
||||||
|
bwrite >>= 1;
|
||||||
|
|
||||||
|
curpixel=0;
|
||||||
|
for (k=0; k!=depth; k++)
|
||||||
|
{
|
||||||
|
curpixel <<=8;
|
||||||
|
curpixel |= xpm[i][j+k];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( curpixel != zero ) {
|
||||||
|
bwrite += 128;
|
||||||
|
}
|
||||||
|
bcount++;
|
||||||
|
if (bcount == 8) {
|
||||||
|
*xbm = bwrite;
|
||||||
|
xbm++;
|
||||||
|
bcount = 0;
|
||||||
|
bwrite = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* copyXPMArea *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
void copyXPMArea(int x, int y, int sx, int sy, int dx, int dy) {
|
||||||
|
|
||||||
|
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* copyXBMArea *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
void copyXBMArea(int x, int y, int sx, int sy, int dx, int dy) {
|
||||||
|
|
||||||
|
XCopyArea(display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* setMaskXY *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
|
||||||
|
void setMaskXY(int x, int y) {
|
||||||
|
|
||||||
|
XShapeCombineMask(display, win, ShapeBounding, x, y, pixmask, ShapeSet);
|
||||||
|
XShapeCombineMask(display, iconwin, ShapeBounding, x, y, pixmask, ShapeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************\
|
||||||
|
|* openXwindow *|
|
||||||
|
\*******************************************************************************/
|
||||||
|
void openXwindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height) {
|
||||||
|
|
||||||
|
unsigned int borderwidth = 1;
|
||||||
|
XClassHint classHint;
|
||||||
|
char *display_name = NULL;
|
||||||
|
char *wname = argv[0];
|
||||||
|
XTextProperty name;
|
||||||
|
|
||||||
|
XGCValues gcv;
|
||||||
|
unsigned long gcm;
|
||||||
|
|
||||||
|
char *geometry = NULL;
|
||||||
|
|
||||||
|
int dummy=0;
|
||||||
|
int i, wx, wy;
|
||||||
|
|
||||||
|
/* Changed to work better with Python. Changed check in for loop to control
|
||||||
|
* argc instead of argv.
|
||||||
|
*/
|
||||||
|
for (i=1; i < argc; i++) {
|
||||||
|
if (!strcmp(argv[i], "-display")) {
|
||||||
|
display_name = argv[i+1];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (!strcmp(argv[i], "-geometry")) {
|
||||||
|
geometry = argv[i+1];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(display = XOpenDisplay(display_name))) {
|
||||||
|
fprintf(stderr, "%s: can't open display %s\n",
|
||||||
|
wname, XDisplayName(display_name));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
screen = DefaultScreen(display);
|
||||||
|
Root = RootWindow(display, screen);
|
||||||
|
d_depth = DefaultDepth(display, screen);
|
||||||
|
x_fd = XConnectionNumber(display);
|
||||||
|
|
||||||
|
/* Convert XPM to XImage */
|
||||||
|
GetXPM(&wmgen, pixmap_bytes);
|
||||||
|
|
||||||
|
/* Create a window to hold the stuff */
|
||||||
|
mysizehints.flags = USSize | USPosition;
|
||||||
|
mysizehints.x = 0;
|
||||||
|
mysizehints.y = 0;
|
||||||
|
|
||||||
|
back_pix = GetColor("white");
|
||||||
|
fore_pix = GetColor("black");
|
||||||
|
|
||||||
|
XWMGeometry(display, screen, Geometry, NULL, borderwidth, &mysizehints,
|
||||||
|
&mysizehints.x, &mysizehints.y,&mysizehints.width,&mysizehints.height, &dummy);
|
||||||
|
|
||||||
|
mysizehints.width = 64;
|
||||||
|
mysizehints.height = 64;
|
||||||
|
|
||||||
|
win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y,
|
||||||
|
mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
|
||||||
|
|
||||||
|
iconwin = XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y,
|
||||||
|
mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
|
||||||
|
|
||||||
|
|
||||||
|
/* Added 2003-06-24 for graceful shutdown. */
|
||||||
|
deleteAtom = XInternAtom(display, "WM_DELETE_WINDOW", 0);
|
||||||
|
XSetWMProtocols(display, win, &deleteAtom, 1);
|
||||||
|
|
||||||
|
|
||||||
|
/* Activate hints */
|
||||||
|
XSetWMNormalHints(display, win, &mysizehints);
|
||||||
|
classHint.res_name = wname;
|
||||||
|
classHint.res_class = wname;
|
||||||
|
XSetClassHint(display, win, &classHint);
|
||||||
|
|
||||||
|
XSelectInput(display, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
|
||||||
|
XSelectInput(display, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
|
||||||
|
|
||||||
|
if (XStringListToTextProperty(&wname, 1, &name) == 0) {
|
||||||
|
fprintf(stderr, "%s: can't allocate window name\n", wname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XSetWMName(display, win, &name);
|
||||||
|
|
||||||
|
/* Create GC for drawing */
|
||||||
|
|
||||||
|
gcm = GCForeground | GCBackground | GCGraphicsExposures;
|
||||||
|
gcv.foreground = fore_pix;
|
||||||
|
gcv.background = back_pix;
|
||||||
|
gcv.graphics_exposures = 0;
|
||||||
|
NormalGC = XCreateGC(display, Root, gcm, &gcv);
|
||||||
|
|
||||||
|
/* ONLYSHAPE ON */
|
||||||
|
|
||||||
|
pixmask = XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width, pixmask_height);
|
||||||
|
|
||||||
|
XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
|
||||||
|
XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
|
||||||
|
|
||||||
|
/* ONLYSHAPE OFF */
|
||||||
|
|
||||||
|
mywmhints.initial_state = WithdrawnState;
|
||||||
|
mywmhints.icon_window = iconwin;
|
||||||
|
mywmhints.icon_x = mysizehints.x;
|
||||||
|
mywmhints.icon_y = mysizehints.y;
|
||||||
|
mywmhints.window_group = win;
|
||||||
|
mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
|
||||||
|
|
||||||
|
XSetWMHints(display, win, &mywmhints);
|
||||||
|
|
||||||
|
XSetCommand(display, win, argv, argc);
|
||||||
|
XMapWindow(display, win);
|
||||||
|
|
||||||
|
if (geometry) {
|
||||||
|
if (sscanf(geometry, "+%d+%d", &wx, &wy) != 2) {
|
||||||
|
fprintf(stderr, "Bad geometry string.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
XMoveWindow(display, win, wx, wy);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
pywmgeneral/pywmgeneral.h
Normal file
66
pywmgeneral/pywmgeneral.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License.
|
||||||
|
* Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WMGENERAL_H_INCLUDED
|
||||||
|
#define WMGENERAL_H_INCLUDED
|
||||||
|
|
||||||
|
/***********/
|
||||||
|
/* Defines */
|
||||||
|
/***********/
|
||||||
|
|
||||||
|
#define MAX_MOUSE_REGION (16)
|
||||||
|
|
||||||
|
/************/
|
||||||
|
/* Typedefs */
|
||||||
|
/************/
|
||||||
|
|
||||||
|
typedef struct _rckeys rckeys;
|
||||||
|
|
||||||
|
struct _rckeys {
|
||||||
|
const char *label;
|
||||||
|
char **var;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _rckeys2 rckeys2;
|
||||||
|
|
||||||
|
struct _rckeys2 {
|
||||||
|
const char *family;
|
||||||
|
const char *label;
|
||||||
|
char **var;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Pixmap pixmap;
|
||||||
|
Pixmap mask;
|
||||||
|
XpmAttributes attributes;
|
||||||
|
} XpmIcon;
|
||||||
|
|
||||||
|
/*******************/
|
||||||
|
/* Global variable */
|
||||||
|
/*******************/
|
||||||
|
|
||||||
|
Display *display;
|
||||||
|
|
||||||
|
/***********************/
|
||||||
|
/* Function Prototypes */
|
||||||
|
/***********************/
|
||||||
|
|
||||||
|
void AddMouseRegion(int index, int left, int top, int right, int bottom);
|
||||||
|
int CheckMouseRegion(int x, int y);
|
||||||
|
|
||||||
|
void openXwindow(int argc, char *argv[], char **, char *, int, int);
|
||||||
|
void RedrawWindow(void);
|
||||||
|
void RedrawWindowXY(int x, int y);
|
||||||
|
|
||||||
|
void createXBMfromXPM(char *, char **, int, int);
|
||||||
|
void copyXPMArea(int, int, int, int, int, int);
|
||||||
|
void copyXBMArea(int, int, int, int, int, int);
|
||||||
|
void setMaskXY(int, int);
|
||||||
|
|
||||||
|
#endif
|
||||||
253
pywmgeneral/pywmhelpers.py
Normal file
253
pywmgeneral/pywmhelpers.py
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
"""pywmhelpers.py
|
||||||
|
|
||||||
|
Various helper functions when writing wm dockapps in Python. This module
|
||||||
|
is way better commented than the pywmgeneral one. This is the one
|
||||||
|
intented for use in applications. Many functions are just wrappers
|
||||||
|
around the ones in pywmgeneral but with nicer interfaces and better
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
|
||||||
|
Licensed under the GNU General Public License
|
||||||
|
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
2003-06-25 Kristoffer Erlandsson
|
||||||
|
Updated documentation
|
||||||
|
|
||||||
|
2003-06-24 Kristoffer Erlandsson
|
||||||
|
Some changes to handle the additional event handling in pywmgeneral
|
||||||
|
|
||||||
|
2003-06-16 Kristoffer Erlandsson
|
||||||
|
First workingish version
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import ConfigParser
|
||||||
|
|
||||||
|
import pywmgeneral
|
||||||
|
|
||||||
|
def readConfigFile(fileName, errOut):
|
||||||
|
"""Read the config file fileName.
|
||||||
|
|
||||||
|
Return a dictionary with the options and values in the DEFAULT
|
||||||
|
section. Ignore everything else. The configuration file should not
|
||||||
|
get so complicated so that sections are needed. errOut is the
|
||||||
|
file-like object to which error messages will be printed.
|
||||||
|
"""
|
||||||
|
if not os.access(fileName, os.R_OK):
|
||||||
|
if errOut:
|
||||||
|
errOut.write(
|
||||||
|
'Configuration file is not readable. Using defaults.\n')
|
||||||
|
return {}
|
||||||
|
cp = ConfigParser.ConfigParser()
|
||||||
|
try:
|
||||||
|
cp.read(fileName)
|
||||||
|
except ConfigParser.Error, e:
|
||||||
|
if errOut:
|
||||||
|
errOut.write('Error in configuration file:\n')
|
||||||
|
errOut.write(str(e) + '\nUsing defaults.')
|
||||||
|
return {}
|
||||||
|
defaults = cp.defaults()
|
||||||
|
if defaults == {}:
|
||||||
|
if errOut:
|
||||||
|
errOut.write(
|
||||||
|
'Missing or empty DEFAULT section in the config file.\n')
|
||||||
|
errOut.write('Using defaults.\n')
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
def getCenterStartPos(s, letterWidth, areaWidth, offset):
|
||||||
|
"""Get the x starting position if we want to paint s centred."""
|
||||||
|
w = len(s) * letterWidth
|
||||||
|
textArea = areaWidth - offset * 2 - 1
|
||||||
|
return (textArea - w) / 2
|
||||||
|
|
||||||
|
def addChar(ch, x, y, letterWidth, letterHeight, lettersStartX, lettersStartY,
|
||||||
|
letters, digitWidth, digitHeight, digitsStartX, digitsStartY,
|
||||||
|
digits, xOffset, yOffset, width, height):
|
||||||
|
"""Paint the character ch at position x, y in the window.
|
||||||
|
|
||||||
|
Return the (width, height) of the character painted. Raise
|
||||||
|
ValueError if we try to paint a char not in letters or digits
|
||||||
|
or if we get out of bounds during painting. digits is really
|
||||||
|
just another line of chars, it's unlucky called digits everywhere
|
||||||
|
I used it since it contained only digits in the start. However,
|
||||||
|
now it contains various special chars too everywhere I use it. But
|
||||||
|
the name remains in too many places so I haven't gotten to change
|
||||||
|
it.
|
||||||
|
"""
|
||||||
|
chIndex = letters.find(ch.lower())
|
||||||
|
if chIndex != -1:
|
||||||
|
chX = lettersStartX + chIndex * letterWidth
|
||||||
|
chY = lettersStartY
|
||||||
|
w = letterWidth
|
||||||
|
h = letterHeight
|
||||||
|
else:
|
||||||
|
chIndex = digits.find(ch)
|
||||||
|
if chIndex != -1:
|
||||||
|
chX = digitsStartX + chIndex * digitWidth
|
||||||
|
chY = digitsStartY
|
||||||
|
w = digitWidth
|
||||||
|
h = digitHeight
|
||||||
|
else:
|
||||||
|
raise ValueError, "Unsupported char: '%s'" % ch
|
||||||
|
targX = x + xOffset
|
||||||
|
targY = y + yOffset
|
||||||
|
if targX + w > width - xOffset or targY + h > height - yOffset\
|
||||||
|
or targX < 0 or targY < 0:
|
||||||
|
raise ValueError, "Out of bounds."
|
||||||
|
pywmgeneral.copyXPMArea(chX, chY, w, h, targX, targY)
|
||||||
|
return (w, h)
|
||||||
|
|
||||||
|
def addString(s, x, y, letterWidth, letterHeight, lettersStartX, lettersStartY,
|
||||||
|
letters, digitWidth, digitHeight, digitsStartX, digitsStartY,
|
||||||
|
digits, xOffset, yOffset, width, height):
|
||||||
|
"""Add a string at the given x and y positions.
|
||||||
|
|
||||||
|
Call addChar repeatedely, so the same exception rules apply."""
|
||||||
|
lastW = 0
|
||||||
|
for letter in s:
|
||||||
|
w, h = addChar(letter, x + lastW, y, letterWidth, letterHeight,
|
||||||
|
lettersStartX, lettersStartY, letters, digitWidth,
|
||||||
|
digitHeight, digitsStartX, digitsStartY, digits,
|
||||||
|
xOffset, yOffset, width, height)
|
||||||
|
lastW += w
|
||||||
|
|
||||||
|
def getVertSpacing(numLines, margin, height, letterHeight, yOffset):
|
||||||
|
"""Return the optimal spacing between a number of lines.
|
||||||
|
|
||||||
|
margin is the space we want between the first line and the top."""
|
||||||
|
h = height - numLines * letterHeight - yOffset * 2 - margin
|
||||||
|
return h / (numLines - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def readXPM(fileName):
|
||||||
|
"""Read the xpm in filename.
|
||||||
|
|
||||||
|
Return a list of strings containing the xpm. Raise IOError if we run
|
||||||
|
into trouble when trying to read the file. This function surely
|
||||||
|
doesn't handle all XPMs, but it handles the ones I use, so that'll
|
||||||
|
do.
|
||||||
|
"""
|
||||||
|
f = file(fileName, 'r')
|
||||||
|
lines = [l.rstrip('\n') for l in f.readlines()]
|
||||||
|
s = ''.join(lines)
|
||||||
|
res = []
|
||||||
|
while 1:
|
||||||
|
nextStrStart = s.find('"')
|
||||||
|
if nextStrStart != -1:
|
||||||
|
nextStrEnd = s.find('"', nextStrStart + 1)
|
||||||
|
if nextStrEnd != -1:
|
||||||
|
res.append(s[nextStrStart+1:nextStrEnd])
|
||||||
|
s = s[nextStrEnd+1:]
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
return res
|
||||||
|
|
||||||
|
def setColor(xpm, name, newColor):
|
||||||
|
"""Find the color with comment name and set this color to newColor.
|
||||||
|
|
||||||
|
Change the source code of an XPM represented as a list of strings.
|
||||||
|
I'm certain that this will fail on many XPMs too, but it'll do for
|
||||||
|
the ones I use. No check is done that the color is valid, this has
|
||||||
|
to be done elsewhere.
|
||||||
|
"""
|
||||||
|
colorRE = re.compile(
|
||||||
|
r"^(?P<letter>.).*?c (?P<color>#.*?) s (?P<comment>.*)")
|
||||||
|
index = 1
|
||||||
|
for line in xpm[1:]:
|
||||||
|
m = colorRE.match(line)
|
||||||
|
if not m is None:
|
||||||
|
comment = m.group('comment')
|
||||||
|
if comment == name:
|
||||||
|
letter = m.group('letter')
|
||||||
|
color = newColor
|
||||||
|
xpm[index] = '%s\tc %s s %s' % (letter, color, comment)
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
def setDefaultPixmap(xpm):
|
||||||
|
"""Set the pixmap of the program.
|
||||||
|
|
||||||
|
xpm is an XPM represented as a list of strings, possible gotten
|
||||||
|
from readXPM(). This is what we use all the time later. The XBM
|
||||||
|
mask is created out of the XPM. If I understand correctly how it
|
||||||
|
works we use the upper left rectangle as mask. This is the
|
||||||
|
simplest way to do it and is the desired behaviour in most cases.
|
||||||
|
"""
|
||||||
|
pywmgeneral.includePixmap(xpm)
|
||||||
|
|
||||||
|
def openXwindow(argv, w, h):
|
||||||
|
"""Open the X window of given width and height.
|
||||||
|
|
||||||
|
The XBM mask is here created from the upper left rectangle of the
|
||||||
|
XPM using the given width and height."""
|
||||||
|
pywmgeneral.openXwindow(len(argv), argv, w, h)
|
||||||
|
|
||||||
|
def redraw():
|
||||||
|
"""Redraw the window."""
|
||||||
|
pywmgeneral.redrawWindow()
|
||||||
|
|
||||||
|
def redrawXY(x, y):
|
||||||
|
"""Redraw a given region of the window."""
|
||||||
|
pywmgeneral.redrawWindowXY(x, y)
|
||||||
|
|
||||||
|
def copyXPMArea(sourceX, sourceY, width, height, targetX, targetY):
|
||||||
|
"""Copy an area of the global XPM."""
|
||||||
|
if width > 0 or height > 0:
|
||||||
|
pywmgeneral.copyXPMArea(sourceX, sourceY, width, height,
|
||||||
|
targetX, targetY)
|
||||||
|
|
||||||
|
def addMouseRegion(index, left, top, right, bottom):
|
||||||
|
"""Add a mouse region in the window."""
|
||||||
|
pywmgeneral.addMouseRegion(index, left, top, right, bottom)
|
||||||
|
|
||||||
|
def checkMouseRegion(x, y):
|
||||||
|
"""Check if x,y is in any mouse region. Return that region, otherwise -1.
|
||||||
|
"""
|
||||||
|
return pywmgeneral.checkMouseRegion(x, y)
|
||||||
|
|
||||||
|
def getEvent():
|
||||||
|
"""Check for XEvents and return one if found.
|
||||||
|
|
||||||
|
Return None if we find no events. There may be events pending still
|
||||||
|
after this function is called. If an event which we handle is found,
|
||||||
|
return a dictionary with information about it. All dictionaries
|
||||||
|
contain a 'type' field identifying the event. Now existing events
|
||||||
|
with dictionary keys are:
|
||||||
|
'buttonrelease':
|
||||||
|
x, y, button
|
||||||
|
'destroynotify':
|
||||||
|
"""
|
||||||
|
return pywmgeneral.checkForEvents()
|
||||||
|
|
||||||
|
def getColorCode(colorName, rgbFileName):
|
||||||
|
"""Convert a color to rgb code usable in an xpm.
|
||||||
|
|
||||||
|
We use the file rgbFileName for looking up the colors. Return None
|
||||||
|
if we find no match. The rgbFileName should be like the one found in
|
||||||
|
/usr/lib/X11R6/rgb.txt on most sytems.
|
||||||
|
"""
|
||||||
|
f = file(rgbFileName, 'r')
|
||||||
|
lines = f.readlines()
|
||||||
|
f.close()
|
||||||
|
for l in lines:
|
||||||
|
if l[0] != '!':
|
||||||
|
words = l.split()
|
||||||
|
if len(words) > 3:
|
||||||
|
name = ' '.join(words[3:])
|
||||||
|
if colorName.lower() == name.lower():
|
||||||
|
# Found the right color, get it's code
|
||||||
|
try:
|
||||||
|
r = int(words[0])
|
||||||
|
g = int(words[1])
|
||||||
|
b = int(words[2])
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
rgbstr = '#' + str(hex(r))[2:].zfill(2) + \
|
||||||
|
str(hex(g))[2:].zfill(2) + \
|
||||||
|
str(hex(b))[2:].zfill(2)
|
||||||
|
return rgbstr
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
26
pywmgeneral/setup.py
Executable file
26
pywmgeneral/setup.py
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
from distutils.core import setup, Extension
|
||||||
|
|
||||||
|
|
||||||
|
# Set these so they match your system.
|
||||||
|
XLibDir = '/usr/X11R6/lib'
|
||||||
|
XIncludes = '/usr/X11R6/include'
|
||||||
|
|
||||||
|
|
||||||
|
module1 = Extension('pywmgeneral',
|
||||||
|
libraries = ['Xpm', 'Xext', 'X11'],
|
||||||
|
library_dirs = [XLibDir],
|
||||||
|
include_dirs = [XIncludes],
|
||||||
|
sources = ['pywmgeneral.c'])
|
||||||
|
|
||||||
|
setup(name = 'pywmgeneral',
|
||||||
|
py_modules = ['pywmhelpers'],
|
||||||
|
version = '0.1',
|
||||||
|
author = 'Kristoffer Erlandsson',
|
||||||
|
author_email = 'krier115@student.liu.se',
|
||||||
|
description = 'Python module for making WindowMaker dockapps.',
|
||||||
|
url = 'http://foo.unix.se/pywmdockapps',
|
||||||
|
license = 'GPL',
|
||||||
|
ext_modules = [module1])
|
||||||
|
|
||||||
8
pywmgeneric/ChangeLog
Normal file
8
pywmgeneric/ChangeLog
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
2003-07-02 Kristoffer Erlandsson
|
||||||
|
* Added support for up to 10 mouse buttons.
|
||||||
|
* The char translation now handles both upper and lower case.
|
||||||
|
|
||||||
|
2003-06-29 Kristoffer Erlandsson
|
||||||
|
* Additional error checking around string interpolations from cfg file.
|
||||||
|
|
||||||
|
|
||||||
13
pywmgeneric/INSTALL
Normal file
13
pywmgeneric/INSTALL
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
1. If you don't have pywmgeneral installed, install it first. Can be found
|
||||||
|
at http://foo.unix.se/pywmdockapps.
|
||||||
|
|
||||||
|
2. Copy pywmgeneric.py to somewhere in your path (like ~/bin or
|
||||||
|
/usr/local/bin).
|
||||||
|
|
||||||
|
3. Create your own pywmgenericrc, save it as ~/.pywmgenericrc. Use the
|
||||||
|
sample.pywmgenericrc as reference.
|
||||||
|
|
||||||
|
4. Enjoy.
|
||||||
|
|
||||||
|
Trouble? E-mail me at <krier115@student.liu.se>.
|
||||||
|
|
||||||
69
pywmgeneric/README
Normal file
69
pywmgeneric/README
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
[WHAT]
|
||||||
|
Pywmgeneric is a dockapp with five entrys that display the first line of
|
||||||
|
output from an external program, the returned string from an python
|
||||||
|
method or an static string. Three mouse actions can be associated with
|
||||||
|
each displayed entry.
|
||||||
|
|
||||||
|
[DETAILED]
|
||||||
|
Five different entries can be defined in pywmgeneric. Every entry can
|
||||||
|
have an action, an update_delay and up to three mouse actions associated
|
||||||
|
with it. Some additional options are also available.
|
||||||
|
|
||||||
|
The associated action of an entry is executed with update_delay time
|
||||||
|
between executions. The output from the action is stored. If no special
|
||||||
|
display options are defined, the application will display the first line
|
||||||
|
of output from the action. If it does not fit in the window, it will
|
||||||
|
slowly scroll in the window. Clicking with the mouse on the text invokes
|
||||||
|
one of the mouse actions, depending on which button was pressed. The
|
||||||
|
action can be to execute an external program, to run a python method or
|
||||||
|
to update the text through performing the action associated with the
|
||||||
|
entry. The mouse actions can retreive the text genererated by the timed
|
||||||
|
action.
|
||||||
|
|
||||||
|
Python methods that should be executed as actions should be defined in
|
||||||
|
the class UserMethods. Look in pywmgeneric.py, near the top, for this
|
||||||
|
class and the documentation of how these methods should be defined.
|
||||||
|
Note that the methods allready there only are samples and will probably
|
||||||
|
not work on your system.
|
||||||
|
|
||||||
|
Other options in the configuration file include:
|
||||||
|
scroll = yes|no - en-/disable scrolling of the text when it doesn't fit
|
||||||
|
display = <text> - display a static string instead of the first line of
|
||||||
|
the action-generated output.
|
||||||
|
|
||||||
|
See the sample configuration file for examples and more information.
|
||||||
|
Note that this file is only for reference, it is the one I use. Things
|
||||||
|
will probably not work on your system if you do not change it.
|
||||||
|
|
||||||
|
[USES]
|
||||||
|
This program is very generic (hence the name ;) ), the uses are many
|
||||||
|
since it is highly configurable.
|
||||||
|
|
||||||
|
I use it for displaying my cpu and system temperatures. I just defined
|
||||||
|
methods for reading two files in the /proc filesystem on my system.
|
||||||
|
|
||||||
|
I also use it for fetching headlines from a newspaper, displaying the
|
||||||
|
first headline fetched. If I click with my left button, all headlines
|
||||||
|
will appear in an xmessage. If I rightclick the headlines along with
|
||||||
|
summaries are displayed, and if I click with my middle button mozilla
|
||||||
|
will fire up showing the newspaper's website.
|
||||||
|
|
||||||
|
I have an external program which displays what's currently on tv,
|
||||||
|
ideal for use with this program I thought! I modified it a bit so
|
||||||
|
it printed a summary line at the top, and voila I have all
|
||||||
|
currently running tv programs scrolling by in an dockapp. And clicking
|
||||||
|
on it shows me the details.
|
||||||
|
|
||||||
|
You could use it as an application launcher, just display the name of
|
||||||
|
the applications and associate mouse actions to lauch them. The
|
||||||
|
xterm-entry in the sample shows this.
|
||||||
|
|
||||||
|
You could probably come up with much more than this!
|
||||||
|
|
||||||
|
[CONTACT]
|
||||||
|
Mail bug reports, suggestions, comments, complaints or anything else,
|
||||||
|
be it funny or boring, related to this program to me, Kristoffer
|
||||||
|
Erlandsson, <krier115@student.liu.se>.
|
||||||
|
|
||||||
|
The newest version can be found at http://foo.unix.se/pywmdockapps/.
|
||||||
|
|
||||||
710
pywmgeneric/pywmgeneric.py
Executable file
710
pywmgeneric/pywmgeneric.py
Executable file
@@ -0,0 +1,710 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
'''pywmgeneric.py
|
||||||
|
|
||||||
|
WindowMaker dockapp to display the output from an external program, or the
|
||||||
|
string returned from a python function. Mouse actions can be associated with
|
||||||
|
the displayed text.
|
||||||
|
|
||||||
|
Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
|
||||||
|
Licensed under the GNU General Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Changes
|
||||||
|
2003-07-02 Kristoffer Erlandsson
|
||||||
|
Added support for up to 10 mouse buttons.
|
||||||
|
The char translation now handles both upper and lower case.
|
||||||
|
|
||||||
|
2003-06-29 Kristoffer Erlandsson
|
||||||
|
Additional error checking around string interpolations from cfg file.
|
||||||
|
|
||||||
|
2003-06-27 Kristoffer Erlandsson
|
||||||
|
First working version
|
||||||
|
'''
|
||||||
|
|
||||||
|
usage = '''pywmgeneric.py [options]
|
||||||
|
Available options are:
|
||||||
|
-h, --help print this help
|
||||||
|
-t, --text <color> set the text color
|
||||||
|
-b, --background <color> set the background color
|
||||||
|
-r, --rgbfile <file> set the rgb file to get color codes from
|
||||||
|
-c, --configfile <file> set the config file to use
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import string
|
||||||
|
import ConfigParser
|
||||||
|
import getopt
|
||||||
|
import popen2
|
||||||
|
|
||||||
|
import pywmhelpers
|
||||||
|
|
||||||
|
class UserMethods:
|
||||||
|
'''Put methods that should be called when the action is method=... here.
|
||||||
|
|
||||||
|
The action methods should return a function, which in turn returns
|
||||||
|
the string to be displayed (if no 'display =' exists) and stored
|
||||||
|
for later retreival.
|
||||||
|
|
||||||
|
The mouse action methods gets the entry instance as an argument. Return
|
||||||
|
value doesn't matter.
|
||||||
|
|
||||||
|
An instance of this class is created at initialization and passed to all
|
||||||
|
entries, so keep in mind that they share the same object.
|
||||||
|
|
||||||
|
THE METHODS ALLREADY HERE ARE JUST SAMPLES AND WILL PROBABLY NOT WORK
|
||||||
|
WITH YOUR SYSTEM.
|
||||||
|
'''
|
||||||
|
def getCpuTemp(self):
|
||||||
|
try:
|
||||||
|
f = file('/proc/sys/dev/sensors/w83697hf-isa-0290/temp2', 'r')
|
||||||
|
except IOError:
|
||||||
|
return lambda: 'error'
|
||||||
|
temp = f.readline().split()[2]
|
||||||
|
f.close()
|
||||||
|
return lambda: 'cpu: %s' % temp
|
||||||
|
|
||||||
|
def getSysTemp(self):
|
||||||
|
try:
|
||||||
|
f = file('/proc/sys/dev/sensors/w83697hf-isa-0290/temp1', 'r')
|
||||||
|
except IOError:
|
||||||
|
return lambda: 'error'
|
||||||
|
temp = f.readline().split()[2]
|
||||||
|
f.close()
|
||||||
|
return lambda: 'sys: %s' % temp
|
||||||
|
|
||||||
|
def showDnWithoutDescs(self, entry):
|
||||||
|
'''Strip descriptions from some text where the descs are indented.
|
||||||
|
|
||||||
|
Display it in an xmessage.
|
||||||
|
'''
|
||||||
|
text = entry.getAllText()
|
||||||
|
s = '\n'.join([x for x in text.split('\n') if not x.startswith(' ')])
|
||||||
|
os.system('xmessage "' + s.replace('"', r'\"') + '" &')
|
||||||
|
|
||||||
|
def showTvWithoutDescs(self, entry):
|
||||||
|
'''Strip descriptions from some text where the descs are indented.
|
||||||
|
|
||||||
|
Display it in an xmessage.
|
||||||
|
'''
|
||||||
|
text = entry.getAllText()
|
||||||
|
s='\n'.join([x for x in
|
||||||
|
text.split('\n')[1:] if not x.startswith(' ')])
|
||||||
|
s = s.replace('\n\n', '\n')
|
||||||
|
os.system('xmessage "' + s.replace('"', r'\"') + '" &')
|
||||||
|
|
||||||
|
width = 64
|
||||||
|
height = 64
|
||||||
|
|
||||||
|
xOffset = 4
|
||||||
|
yOffset = 4
|
||||||
|
|
||||||
|
lettersStartX = 0
|
||||||
|
lettersStartY = 74
|
||||||
|
letterWidth = 6
|
||||||
|
letterHeight = 8
|
||||||
|
|
||||||
|
digitsStartX = 0
|
||||||
|
digitsStartY = 64
|
||||||
|
digitWidth = 6
|
||||||
|
digitHeight = 8
|
||||||
|
|
||||||
|
letters = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
|
digits = '0123456789:/-%. '
|
||||||
|
|
||||||
|
maxChars = 9
|
||||||
|
|
||||||
|
defaultConfigFile = '~/.pywmgenericrc'
|
||||||
|
defaultRGBFiles = ('/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt')
|
||||||
|
|
||||||
|
err = sys.stderr.write
|
||||||
|
|
||||||
|
def addString(s, x, y):
|
||||||
|
'''Convenience function around pwymhelpers.addString.'''
|
||||||
|
try:
|
||||||
|
pywmhelpers.addString(s, x, y, letterWidth, letterHeight, lettersStartX,
|
||||||
|
lettersStartY, letters, digitWidth, digitHeight,
|
||||||
|
digitsStartX, digitsStartY, digits, xOffset, yOffset,
|
||||||
|
width, height)
|
||||||
|
except ValueError, e:
|
||||||
|
sys.stderr.write('Error when painting string:\n' + str(e) + '\n')
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
def clearLine(y):
|
||||||
|
'''Clear a line of text at position y.'''
|
||||||
|
pywmhelpers.copyXPMArea(72, yOffset, width - 2 * xOffset, letterHeight,
|
||||||
|
xOffset, y + yOffset)
|
||||||
|
|
||||||
|
def getXY(line):
|
||||||
|
'''Return the x and y positions to be used at line line.'''
|
||||||
|
return 0, line * (letterHeight + 3) + 1
|
||||||
|
|
||||||
|
def isTrue(s):
|
||||||
|
'''Return true if the string s can be interpreted as a true value.
|
||||||
|
|
||||||
|
Raises ValueError if we get a string we don't like.
|
||||||
|
'''
|
||||||
|
trueThings = ['on', 'yes', '1', 'true']
|
||||||
|
falseThings = ['off', 'no', '0', 'false']
|
||||||
|
if s in trueThings:
|
||||||
|
return 1
|
||||||
|
elif s in falseThings:
|
||||||
|
return 0
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
|
||||||
|
class Entry:
|
||||||
|
def __init__(self, line, updateDelay, action, mouseActions,
|
||||||
|
userMethods, display=None, scrollText=1):
|
||||||
|
self._updateDelay = updateDelay
|
||||||
|
self._line = line
|
||||||
|
self._action = self._parseAction(action)
|
||||||
|
self._mouseActions = [self._parseAction(a) for a in mouseActions]
|
||||||
|
self._userMethods = userMethods
|
||||||
|
self._display = display
|
||||||
|
self._scrollText = scrollText
|
||||||
|
|
||||||
|
self._scrollPos = 0
|
||||||
|
self._tickCount = 0L
|
||||||
|
|
||||||
|
self._runningProcs = []
|
||||||
|
self._actionProc = None
|
||||||
|
self._getTextMethod = None
|
||||||
|
self._allText = ''
|
||||||
|
self._displayLine = ''
|
||||||
|
# Do one action when we start, so we are sure that one gets done even
|
||||||
|
# if we do not want any other updates.
|
||||||
|
self._doAction()
|
||||||
|
self._lastActionAt = time.time()
|
||||||
|
|
||||||
|
def _parseAction(self, action):
|
||||||
|
'''Parse an action string, return (<action>, <argument string>).
|
||||||
|
|
||||||
|
Or none if we get an empty action.'''
|
||||||
|
if action:
|
||||||
|
whatToDo = action.split()[0]
|
||||||
|
argStr = action[len(whatToDo):].lstrip()
|
||||||
|
return (whatToDo, argStr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _execExternal(self, command):
|
||||||
|
'''Exec an external command in the background.
|
||||||
|
|
||||||
|
Return the running process as created by Popen3().'''
|
||||||
|
proc = popen2.Popen3(command)
|
||||||
|
self._runningProcs.append(proc)
|
||||||
|
return proc
|
||||||
|
|
||||||
|
def _doMouseAction(self, button):
|
||||||
|
'''Perform the mouse action associated with a button.'''
|
||||||
|
if len(self._mouseActions) < button:
|
||||||
|
return # Just for safety, shouldn't happen.
|
||||||
|
item = self._mouseActions[button - 1]
|
||||||
|
if item:
|
||||||
|
# We have an action associated with the button.
|
||||||
|
action, arg = item
|
||||||
|
else:
|
||||||
|
# No action associated with the button.
|
||||||
|
return
|
||||||
|
if action == 'exec':
|
||||||
|
self._execExternal(self._expandStr(arg))
|
||||||
|
elif action == 'method':
|
||||||
|
try:
|
||||||
|
method = getattr(self._userMethods, arg)
|
||||||
|
except AttributeError:
|
||||||
|
method = None
|
||||||
|
if method:
|
||||||
|
method(self)
|
||||||
|
else:
|
||||||
|
err("Warning: Method %s does not exist." % arg)
|
||||||
|
elif action == 'update':
|
||||||
|
self._doAction()
|
||||||
|
else:
|
||||||
|
err("Warning: Unknown mouse action: %s, ignoring.\n" % action)
|
||||||
|
|
||||||
|
def _doAction(self):
|
||||||
|
'''Perform the action associated with this entry.'''
|
||||||
|
if self._action is None:
|
||||||
|
return
|
||||||
|
action, arg = self._action
|
||||||
|
if action == 'exec':
|
||||||
|
if self._actionProc is None :
|
||||||
|
self._actionProc = self._execExternal(arg)
|
||||||
|
else:
|
||||||
|
if not self._actionProc in self._runningProcs:
|
||||||
|
# The action process since the last time is finished, we
|
||||||
|
# can start another one without risking that we get
|
||||||
|
# flooded by processes.
|
||||||
|
self._actionProc = self._execExternal(arg)
|
||||||
|
self._getTextMethod = self._readFromActionProc
|
||||||
|
elif action == 'method':
|
||||||
|
try:
|
||||||
|
method = getattr(self._userMethods, arg)
|
||||||
|
except AttributeError:
|
||||||
|
method = None
|
||||||
|
if method:
|
||||||
|
self._getTextMethod = method()
|
||||||
|
else:
|
||||||
|
err('Warning: method %s does not exist. Ignoring.\n' % arg)
|
||||||
|
else:
|
||||||
|
err("Warning: Unknown action: %s, ignoring.\n" % action)
|
||||||
|
|
||||||
|
def _readFromActionProc(self):
|
||||||
|
'''If our action process is ready, return the output. Otherwise None.
|
||||||
|
'''
|
||||||
|
if self._actionProc.poll() == -1:
|
||||||
|
# Wait until the process is ready before we really read the text.
|
||||||
|
return None
|
||||||
|
# fromchild.read() will return '' if we allready have read the output
|
||||||
|
# so there will be no harm in calling this method more times.
|
||||||
|
return self._actionProc.fromchild.read()
|
||||||
|
|
||||||
|
def _reapZombies(self):
|
||||||
|
'''Poll all running childs. This will reap all zombies.'''
|
||||||
|
i = 0
|
||||||
|
for p in self._runningProcs:
|
||||||
|
val = p.poll()
|
||||||
|
if val != -1:
|
||||||
|
self._runningProcs.pop(i)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
def _updateText(self):
|
||||||
|
'''Get the text, update the display if it has changed.
|
||||||
|
'''
|
||||||
|
text = ''
|
||||||
|
if self._getTextMethod:
|
||||||
|
text = self._getTextMethod()
|
||||||
|
# Only change the text if we get anything from the getTextMethod()
|
||||||
|
if text:
|
||||||
|
self._allText = text
|
||||||
|
if self._display is None:
|
||||||
|
# We have no display = in the config file, we want to
|
||||||
|
# display the first line of the output of the action.
|
||||||
|
if text:
|
||||||
|
displayLine = text.split(os.linesep)[0]
|
||||||
|
else:
|
||||||
|
displayLine = self._displayLine
|
||||||
|
else:
|
||||||
|
displayLine = self._display
|
||||||
|
if displayLine != self._displayLine:
|
||||||
|
# Line to display has changed, display the new one.
|
||||||
|
self._displayLine = displayLine
|
||||||
|
self._scrollPos = 0
|
||||||
|
self.displayText(displayLine)
|
||||||
|
elif len(self._displayLine) > maxChars and self._scrollText:
|
||||||
|
# Line is the same and is longer than the display and we
|
||||||
|
# want to scroll it.
|
||||||
|
if self._tickCount % 2 == 0:
|
||||||
|
# Only scroll every third tick.
|
||||||
|
self._scrollAndDisplay()
|
||||||
|
|
||||||
|
def _scrollAndDisplay(self):
|
||||||
|
'''Scroll the text one step to the left and redisplay it.
|
||||||
|
|
||||||
|
When reaching the end, paint number of spaces before scrolling in the
|
||||||
|
same line again from the right.
|
||||||
|
'''
|
||||||
|
if self._scrollPos >= \
|
||||||
|
len(self._displayLine) + (maxChars - 4):
|
||||||
|
self._scrollPos = 0
|
||||||
|
self.displayText(self._displayLine)
|
||||||
|
elif self._scrollPos >= len(self._displayLine) - 3:
|
||||||
|
self._scrollPos += 1
|
||||||
|
disp = self._displayLine[self._scrollPos:] + \
|
||||||
|
' ' * (maxChars - 3)
|
||||||
|
diff = self._scrollPos - len(self._displayLine)
|
||||||
|
if diff > 0:
|
||||||
|
disp = disp[diff:]
|
||||||
|
disp += self._displayLine
|
||||||
|
self.displayText(disp)
|
||||||
|
else:
|
||||||
|
self._scrollPos += 1
|
||||||
|
self.displayText(
|
||||||
|
self._displayLine[self._scrollPos:])
|
||||||
|
|
||||||
|
def tick1(self):
|
||||||
|
'''Do things that should be done often.
|
||||||
|
'''
|
||||||
|
self._tickCount += 1
|
||||||
|
self._reapZombies()
|
||||||
|
self._updateText()
|
||||||
|
currTime = time.time()
|
||||||
|
if not self._updateDelay is None and \
|
||||||
|
currTime - self._lastActionAt > self._updateDelay:
|
||||||
|
# We want to do this last in the tick so the command gets the time
|
||||||
|
# to finish before the next tick (if it's a fast one).
|
||||||
|
self._lastActionAt = currTime
|
||||||
|
self._doAction()
|
||||||
|
|
||||||
|
def tick2(self):
|
||||||
|
'''Do things that should be done a bit less often.
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def translateText(self, text):
|
||||||
|
'''Translate chars that can't be painted in the app to something nicer.
|
||||||
|
|
||||||
|
Or nothing if we can't come up with something good. Could be nice to
|
||||||
|
extend this function with chars more fitting for your language.
|
||||||
|
'''
|
||||||
|
fromChars = 'åäöèü'
|
||||||
|
toChars = 'aaoeu'
|
||||||
|
deleteChars = []
|
||||||
|
for c in text.lower():
|
||||||
|
if not (c in letters or c in digits or c in fromChars):
|
||||||
|
deleteChars.append(c)
|
||||||
|
deleteChars = ''.join(deleteChars)
|
||||||
|
trans = string.maketrans(fromChars, toChars)
|
||||||
|
text = string.translate(text.lower(), trans, deleteChars)
|
||||||
|
return text
|
||||||
|
|
||||||
|
def getAllText(self):
|
||||||
|
return self._allText
|
||||||
|
|
||||||
|
def getDisplayedLine(self):
|
||||||
|
return self._displayLine
|
||||||
|
|
||||||
|
def _expandStr(self, s):
|
||||||
|
'''Expand s, which now should be a line from an on_mouseX field.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
res = s % {'allText' : self._allText,
|
||||||
|
'displayedLine' : self._displayLine,
|
||||||
|
'allTextEscaped' : self._allText.replace('"', r'\"'),
|
||||||
|
'allTextButFirstLine' :
|
||||||
|
'\n'.join(self._allText.split('\n')[1:]),
|
||||||
|
'allTextButFirstLineEscaped' :
|
||||||
|
'\n'.join(self._allText.replace('"', '\"').
|
||||||
|
split('\n')[1:])}
|
||||||
|
except (KeyError, TypeError, ValueError):
|
||||||
|
err(
|
||||||
|
"Warning: %s doesn't expand correctly. Ignoring interpolations.\n"
|
||||||
|
% s)
|
||||||
|
res = s
|
||||||
|
return res
|
||||||
|
|
||||||
|
def displayText(self, text):
|
||||||
|
'''Display text on the entry's line.
|
||||||
|
|
||||||
|
Remove or translate characters that aren't supported. Truncate the text
|
||||||
|
to fit in the app.
|
||||||
|
'''
|
||||||
|
x, y = getXY(self._line)
|
||||||
|
clearLine(y)
|
||||||
|
addString(self.translateText(text)[:maxChars], x, y)
|
||||||
|
|
||||||
|
def mouseClicked(self, button):
|
||||||
|
'''A mouse button has been clicked, do things.'''
|
||||||
|
if 0 < button < 11:
|
||||||
|
self._doMouseAction(button)
|
||||||
|
|
||||||
|
class PywmGeneric:
|
||||||
|
def __init__(self, config):
|
||||||
|
self._entrys = []
|
||||||
|
line = 0
|
||||||
|
um = UserMethods()
|
||||||
|
for c in config:
|
||||||
|
# Create our 5 entrys.
|
||||||
|
if not c:
|
||||||
|
self._entrys.append(None)
|
||||||
|
line += 1
|
||||||
|
continue
|
||||||
|
delay = c.get('update_delay')
|
||||||
|
if not delay is None:
|
||||||
|
try:
|
||||||
|
delay = self.parseTimeStr(delay)
|
||||||
|
except ValueError:
|
||||||
|
err("Malformed update_delay in section %s. "
|
||||||
|
% str(i))
|
||||||
|
err("Ignoring this section.\n")
|
||||||
|
self._entrys.append(None)
|
||||||
|
line += 1
|
||||||
|
continue
|
||||||
|
action = c.get('action')
|
||||||
|
display = c.get('display')
|
||||||
|
if action is None and display is None:
|
||||||
|
err(
|
||||||
|
"Warning: No action or display in section %d, ignoring it.\n"
|
||||||
|
% i)
|
||||||
|
self._entrys.append(None)
|
||||||
|
else:
|
||||||
|
scroll = isTrue(c.get('scroll', '1'))
|
||||||
|
# Get the mouse actions.
|
||||||
|
mouseActions = []
|
||||||
|
for i in range(10):
|
||||||
|
but = str(i + 1)
|
||||||
|
opt = 'on_mouse' + but
|
||||||
|
mouseActions.append(c.get(opt))
|
||||||
|
self._entrys.append(Entry(line, delay, action,
|
||||||
|
mouseActions, um, display, scroll))
|
||||||
|
line += 1
|
||||||
|
self._setupMouseRegions()
|
||||||
|
|
||||||
|
def _setupMouseRegions(self):
|
||||||
|
for i in range(5):
|
||||||
|
x, y = getXY(i)
|
||||||
|
if not self._entrys[i] is None:
|
||||||
|
pywmhelpers.addMouseRegion(i, x + xOffset, y + yOffset,
|
||||||
|
width - 2 * xOffset, y + yOffset + letterHeight)
|
||||||
|
|
||||||
|
def parseTimeStr(self, timeStr):
|
||||||
|
'''Take a string on a form like 10h and return the number of seconds.
|
||||||
|
|
||||||
|
Raise ValueError if timeStr is on a bad format.
|
||||||
|
'''
|
||||||
|
multipliers = {'s' : 1, 'm' : 60, 'h' : 3600}
|
||||||
|
timeStr = timeStr.strip()
|
||||||
|
if timeStr:
|
||||||
|
timeLetter = timeStr[-1]
|
||||||
|
multiplier = multipliers.get(timeLetter)
|
||||||
|
if not multiplier is None:
|
||||||
|
timeNum = float(timeStr[:-1].strip())
|
||||||
|
numSecs = timeNum * multiplier
|
||||||
|
return numSecs
|
||||||
|
raise ValueError, 'Invalid literal'
|
||||||
|
|
||||||
|
def _checkForEvents(self):
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
while not event is None:
|
||||||
|
if event['type'] == 'destroynotify':
|
||||||
|
sys.exit(0)
|
||||||
|
elif event['type'] == 'buttonrelease':
|
||||||
|
region = pywmhelpers.checkMouseRegion(event['x'], event['y'])
|
||||||
|
button = event['button']
|
||||||
|
if region != -1:
|
||||||
|
if not self._entrys[region] is None:
|
||||||
|
self._entrys[region].mouseClicked(button)
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
|
||||||
|
def mainLoop(self):
|
||||||
|
counter = -1
|
||||||
|
while 1:
|
||||||
|
counter += 1
|
||||||
|
self._checkForEvents()
|
||||||
|
if counter % 3 == 0:
|
||||||
|
[e.tick1() for e in self._entrys if not e is None]
|
||||||
|
if counter % 100 == 0:
|
||||||
|
[e.tick2() for e in self._entrys if not e is None]
|
||||||
|
|
||||||
|
if counter == 999999:
|
||||||
|
counter = -1
|
||||||
|
pywmhelpers.redraw()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
def parseCommandLine(argv):
|
||||||
|
'''Parse the commandline. Return a dictionary with options and values.'''
|
||||||
|
shorts = 'ht:b:r:c:'
|
||||||
|
longs = ['help', 'text=', 'background=', 'rgbfile=', 'configfile=']
|
||||||
|
try:
|
||||||
|
opts, nonOptArgs = getopt.getopt(argv[1:], shorts, longs)
|
||||||
|
except getopt.GetoptError, e:
|
||||||
|
err('Error when parsing commandline: ' + str(e) + '\n')
|
||||||
|
err(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 ('-t', '--text'):
|
||||||
|
d['textcolor'] = a
|
||||||
|
if o in ('-b', '--background'):
|
||||||
|
d['background'] = a
|
||||||
|
if o in ('-r', '--rgbfile'):
|
||||||
|
d['rgbfile'] = a
|
||||||
|
if o in ('-c', '--configfile'):
|
||||||
|
d['configfile'] = a
|
||||||
|
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):
|
||||||
|
err(
|
||||||
|
"Can't read the RGB file, try setting it differently using -r,\n")
|
||||||
|
err(
|
||||||
|
"Ignoring your color settings, using the defaults.\n")
|
||||||
|
useColors = 0
|
||||||
|
if useColors:
|
||||||
|
# Colors is a list with (<config_key>, <xpm-key>) pairs.
|
||||||
|
colors = (('barfgcolor', 'graph'),
|
||||||
|
('barbgcolor', 'graphbg'),
|
||||||
|
('textcolor', 'text'),
|
||||||
|
('background', 'background'))
|
||||||
|
for key, value in colors:
|
||||||
|
col = config.get(key)
|
||||||
|
if not col is None:
|
||||||
|
code = pywmhelpers.getColorCode(col, rgbFileName)
|
||||||
|
if code is None:
|
||||||
|
err('Bad colorcode for %s, ignoring.\n' % key)
|
||||||
|
else:
|
||||||
|
pywmhelpers.setColor(xpm, value, code)
|
||||||
|
|
||||||
|
def readConfigFile(fileName):
|
||||||
|
'''Read the config file.
|
||||||
|
|
||||||
|
Return a list with dictionaries with the options and values in sections
|
||||||
|
[0]-[4].
|
||||||
|
'''
|
||||||
|
fileName = os.path.expanduser(fileName)
|
||||||
|
if not os.access(fileName, os.R_OK):
|
||||||
|
err("Can't read the configuration file %s.\n" % fileName)
|
||||||
|
# We can't do much without a configuration file
|
||||||
|
sys.exit(3)
|
||||||
|
cp = ConfigParser.ConfigParser()
|
||||||
|
try:
|
||||||
|
cp.read(fileName)
|
||||||
|
except ConfigParser.Error, e:
|
||||||
|
err("Error when reading configuration file:\n%s\n" % str(e))
|
||||||
|
sys.exit(3)
|
||||||
|
l = [{}, {}, {}, {}, {}]
|
||||||
|
for i in range(5):
|
||||||
|
strI = str(i)
|
||||||
|
if cp.has_section(strI):
|
||||||
|
for o in cp.options(strI):
|
||||||
|
l[i][o] = cp.get(strI, o, raw=1)
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
clConfig = parseCommandLine(sys.argv)
|
||||||
|
configFile = clConfig.get('configfile', defaultConfigFile)
|
||||||
|
configFile = os.path.expanduser(configFile)
|
||||||
|
config = readConfigFile(configFile)
|
||||||
|
parseColors(defaultRGBFiles, clConfig, xpm)
|
||||||
|
try:
|
||||||
|
programName = sys.argv[0].split(os.sep)[-1]
|
||||||
|
except IndexError:
|
||||||
|
programName = ''
|
||||||
|
sys.argv[0] = programName
|
||||||
|
pywmhelpers.setDefaultPixmap(xpm)
|
||||||
|
pywmhelpers.openXwindow(sys.argv, width, height)
|
||||||
|
pywmgeneric = PywmGeneric(config)
|
||||||
|
pywmgeneric.mainLoop()
|
||||||
|
|
||||||
|
xpm = \
|
||||||
|
['160 100 13 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',
|
||||||
|
'X\tc #000000000000 s background',
|
||||||
|
'%\tc #2081B2CAAEBA s text',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' ...............................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XXX%XXX%%%%%X%%%%%X%XXX%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%XXXXXXXXXX%XXXXXXXXXX%X%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XX%%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXXX%XXXXXXXXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%%%%%XX%%%%X%%%%%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXXXXXX%XXX%%%%%XXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XXXXXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XX%%XXXX%XXXXXXXXXXXX%XXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XX%%%XX%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XX%%XXXX%XXXXXXXXXXXX%X%XXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'XX%%%XX%%%%XXX%%%%X%%%%XX%%%%XX%%%%%X%%%%%X%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%XXX%X%%%%XX%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%%%%%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%%X%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%X%XXX%X%XXX%XXXXX%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%X%X%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%XX%X%XX%XXX%XXXX%XXXXX',
|
||||||
|
'X%%%%%X%%%%XX%XXXXX%XXX%X%%%%XX%%%%XX%X%%%X%%%%%XXX%XXXXXXX%X%%%XXX%XXXXX%XXX%X%XXX%X%XXX%X%%%%%X%%XX%X%%%%XX%%%%%XXX%XXX%XXX%X%XXX%X%XXX%XXX%XXX%%%%%XXX%XXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%X%X%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%X%X%XX%X%XXXXXX%XX%XXXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXX%XXX%X%XXX%X%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%XX%%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%%X%%X%XXX%XXXXX%X%XXXXXXXX',
|
||||||
|
'X%XXX%X%%%%XXX%%%%X%%%%XX%%%%XX%XXXXX%%%%%X%XXX%XXX%XXXX%%%XX%XXX%X%%%%XX%XXX%X%XXX%X%%%%%X%XXXXX%%%%%X%XXX%X%%%%%XXX%XXXX%%%%XX%%%XX%XXX%X%XXX%X%%%%%X%%%%%XXXX',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................']
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
69
pywmgeneric/sample.pywmgenericrc
Normal file
69
pywmgeneric/sample.pywmgenericrc
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Sample configuration file for pywmgeneric.py.
|
||||||
|
#
|
||||||
|
# THIS IS ONLY A SAMPLE. IT WILL MOST CERTAIN NOT WORK ON YOUR SYSTEM SINCE
|
||||||
|
# CUSTOM PROGRAMS ARE USED IN HERE. ONLY USE THIS AS AN REFERENCE.
|
||||||
|
#
|
||||||
|
# Available actions are:
|
||||||
|
# * method <method> - Call a method defined in the class UserMethods. See the
|
||||||
|
# source file for more information
|
||||||
|
# * exec <command> - Execute an external command
|
||||||
|
#
|
||||||
|
# Available mouse actions are:
|
||||||
|
# * method <method> - Same as above, see the source file for more information.
|
||||||
|
# * exec <command> - Same as above
|
||||||
|
# * update - Update the data through running the action.
|
||||||
|
#
|
||||||
|
# Other options:
|
||||||
|
# * scroll = yes|no - en-/disable scrolling of the text if it doens't fit.
|
||||||
|
# * display = <text> - display a static string instead of the first line of
|
||||||
|
# the action-generated output.
|
||||||
|
# * update_delay = <number><s|m|h> - the time to elapse between performing the
|
||||||
|
# action
|
||||||
|
#
|
||||||
|
# %(allText)s expands to all the text collected by the action.
|
||||||
|
# %(displayedLine)s expands to the line currently displayed in the app. This
|
||||||
|
# may show more than actually displayed since it gets the
|
||||||
|
# entire line, which may be truncated before display.
|
||||||
|
# %(allTextEscaped)s expands to the same as %(allText)s but with all ":s
|
||||||
|
# escaped to \". Great to use when passing the text as a
|
||||||
|
# command line argument to something.
|
||||||
|
# %(allTextButFirstLine)s expands to all text but leaves out the first line.
|
||||||
|
# Useful if your program for example prints a summary
|
||||||
|
# first.
|
||||||
|
# %(allTextButFirstLineEscaped)s is a combination of the two above.
|
||||||
|
#
|
||||||
|
|
||||||
|
[0]
|
||||||
|
action = method getCpuTemp
|
||||||
|
update_delay = 10s
|
||||||
|
on_mouse1 = exec sensors | xmessage -file -
|
||||||
|
on_mouse3 = update
|
||||||
|
scroll = no
|
||||||
|
|
||||||
|
[1]
|
||||||
|
action = method getSysTemp
|
||||||
|
update_delay = 10s
|
||||||
|
on_mouse1 = exec sensors | xmessage -file -
|
||||||
|
on_mouse3 = update
|
||||||
|
scroll = no
|
||||||
|
|
||||||
|
[2]
|
||||||
|
action = exec tvcatcher.py -s -d
|
||||||
|
on_mouse1 = method showTvWithoutDescs
|
||||||
|
on_mouse2 = exec mozilla http://tvprogram.nu
|
||||||
|
on_mouse3 = exec xmessage "%(allTextButFirstLineEscaped)s"
|
||||||
|
update_delay = 5m
|
||||||
|
scroll = yes
|
||||||
|
|
||||||
|
[3]
|
||||||
|
display = xterm
|
||||||
|
on_mouse1 = exec xterm
|
||||||
|
|
||||||
|
[4]
|
||||||
|
action = exec dnheadlinecatcher.py -d
|
||||||
|
on_mouse1 = method showDnWithoutDescs
|
||||||
|
on_mouse2 = exec mozilla http://www.dn.se
|
||||||
|
on_mouse3 = exec xmessage "%(allTextEscaped)s"
|
||||||
|
update_delay = 0.5h
|
||||||
|
scroll = yes
|
||||||
|
|
||||||
8
pywmhdmon/INSTALL
Normal file
8
pywmhdmon/INSTALL
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
1. If you don't have pywmgeneral installed, install it first. Can be found
|
||||||
|
at http://foo.unix.se/pywmdockapps
|
||||||
|
|
||||||
|
2. Copy pywmhdmon.py to somewhere in your path (like ~/bin or
|
||||||
|
/usr/local/bin).
|
||||||
|
|
||||||
|
3. Copy the sample.pywmhdmon to ~/.pywmhdmon and edit as you like.
|
||||||
|
|
||||||
16
pywmhdmon/README
Normal file
16
pywmhdmon/README
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[WHAT]
|
||||||
|
pywmhdmon is a WindowMaker dockapp that displays the available space on
|
||||||
|
up to four of your filesystems. It also contains a bar showing the
|
||||||
|
current HD activity. It currently only works on system which has a
|
||||||
|
/proc/stat like file. The application is easy to configure, invoke it
|
||||||
|
with --help or see the sample rc-file for more information.
|
||||||
|
|
||||||
|
[WHY]
|
||||||
|
As usual, I didn't find a dockapp that fitted me. And I really like to
|
||||||
|
see the current disk activity since my disks are so quiet that I can't
|
||||||
|
hear when they work.
|
||||||
|
|
||||||
|
[CONTACT]
|
||||||
|
Mail anything related to this program to me, Kristoffer Erlandsson,
|
||||||
|
<krier115@student.liu.se>
|
||||||
|
|
||||||
521
pywmhdmon/pywmhdmon.py
Executable file
521
pywmhdmon/pywmhdmon.py
Executable file
@@ -0,0 +1,521 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
'''pywmhdmon.py
|
||||||
|
|
||||||
|
WindowMaker dockapp to monitor the free space on your partitions and
|
||||||
|
the disk activity.
|
||||||
|
|
||||||
|
Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
|
||||||
|
Licensed under the GNU General Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Changes
|
||||||
|
2003-09-01 Kristoffer Erlandsson
|
||||||
|
Fixed a bug where the numbers wouldn't show if they were between 1000 and 1024.
|
||||||
|
|
||||||
|
2003-06-25 Kristoffer Erlandsson
|
||||||
|
Fixed a bug where a mouse click caused the app to enter an infinite loop
|
||||||
|
|
||||||
|
2003-06-24 Kristoffer Erlandsson
|
||||||
|
Additional fine tuning
|
||||||
|
|
||||||
|
2003-06-23 Kristoffer Erlandsson
|
||||||
|
First working version
|
||||||
|
|
||||||
|
'''
|
||||||
|
usage = '''pywmhdmon.py [options]
|
||||||
|
Available options are:
|
||||||
|
-h, --help print this help
|
||||||
|
-t, --textcolor <color> set the text color
|
||||||
|
-f, --barfgcolor <color> set the foregroundcolor of the act. bar
|
||||||
|
-g, --barbgcolor <color> set the background color of the act. bar
|
||||||
|
-b, --background <color> set the background color
|
||||||
|
-r, --rgbfile <file> set the rgb file to get color codes from
|
||||||
|
-c, --configfile <file> set the config file to use
|
||||||
|
-p, --procstat <file> set the location of /proc/stat
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pywmhelpers
|
||||||
|
|
||||||
|
width = 64
|
||||||
|
height = 64
|
||||||
|
|
||||||
|
xOffset = 4
|
||||||
|
yOffset = 4
|
||||||
|
|
||||||
|
lettersStartX = 0
|
||||||
|
lettersStartY = 74
|
||||||
|
letterWidth = 6
|
||||||
|
letterHeight = 8
|
||||||
|
|
||||||
|
digitsStartX = 0
|
||||||
|
digitsStartY = 64
|
||||||
|
digitWidth = 6
|
||||||
|
digitHeight = 8
|
||||||
|
|
||||||
|
graphStartX = 7
|
||||||
|
graphStartY = 53
|
||||||
|
graphHeight = 4
|
||||||
|
|
||||||
|
graphBgStartX = 72
|
||||||
|
graphBgStartY = 53
|
||||||
|
|
||||||
|
graphLineStartX = 66
|
||||||
|
graphLineStartY = 58
|
||||||
|
|
||||||
|
letters = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
|
digits = '0123456789:/-%. '
|
||||||
|
|
||||||
|
defaultConfigFile = '~/.pywmhdmonrc'
|
||||||
|
defaultRGBFiles = ('/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt')
|
||||||
|
defaultProcStat = '/proc/stat'
|
||||||
|
displayModes = ('bar', 'percent', 'free')
|
||||||
|
defaultMode = 'bar'
|
||||||
|
|
||||||
|
class PywmHDMon:
|
||||||
|
def __init__(self, pathsToMonitor, procStat='/proc/stat', actMonEnabled=1):
|
||||||
|
self._pathsToMonitor = pathsToMonitor
|
||||||
|
self._actMonEnabled = actMonEnabled
|
||||||
|
|
||||||
|
self._statFile = procStat
|
||||||
|
self._maxIODiff = 0
|
||||||
|
self._lastIO = -1
|
||||||
|
|
||||||
|
def addString(self, s, x, y):
|
||||||
|
try:
|
||||||
|
pywmhelpers.addString(s, x, y, letterWidth, letterHeight,
|
||||||
|
lettersStartX, lettersStartY, letters, digitWidth,
|
||||||
|
digitHeight, digitsStartX, digitsStartY, digits,
|
||||||
|
xOffset, yOffset, width, height)
|
||||||
|
except ValueError, e:
|
||||||
|
sys.stderr.write('Error when painting string:\n' + str(e) + '\n')
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
def getHdInfo(self, path):
|
||||||
|
'''Get the free and total space of the filesystem which path is on.
|
||||||
|
|
||||||
|
Return a tuple with (<total space>, <free space>) in bytes. Raise
|
||||||
|
OSError if we can't stat the path.
|
||||||
|
These operations are quite costly, not adviced to perform these checks
|
||||||
|
more than once every 10 seconds.
|
||||||
|
'''
|
||||||
|
stat = os.statvfs(path)
|
||||||
|
blockSize = stat.f_bsize
|
||||||
|
availableBlocks = stat.f_bavail
|
||||||
|
totalBlocks = stat.f_blocks
|
||||||
|
free = blockSize * availableBlocks
|
||||||
|
total = blockSize * totalBlocks
|
||||||
|
return (total, free)
|
||||||
|
|
||||||
|
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:
|
||||||
|
pywmhelpers.copyXPMArea(
|
||||||
|
graphLineStartX, graphLineStartY, paintWidth, graphHeight,
|
||||||
|
x + xOffset, y + yOffset)
|
||||||
|
if w - paintWidth > 0:
|
||||||
|
pywmhelpers.copyXPMArea(
|
||||||
|
graphBgStartX, graphBgStartY, w - paintWidth, graphHeight,
|
||||||
|
x + paintWidth + xOffset, y + yOffset)
|
||||||
|
|
||||||
|
def getY(self, line):
|
||||||
|
return 2 + (line - 1) * (letterHeight + 3)
|
||||||
|
|
||||||
|
def paintLabel(self, line, label):
|
||||||
|
self.addString(label, 1, self.getY(line))
|
||||||
|
|
||||||
|
def paintHdData(self, line, data, mode):
|
||||||
|
total, free = data
|
||||||
|
xStart = width - xOffset - 6 * letterWidth - 1
|
||||||
|
if mode == 'percent':
|
||||||
|
percent = (float(free) / float(total)) * 100.0
|
||||||
|
percentStr = (str(int(round(percent))) + '%').rjust(5)
|
||||||
|
self.addString(percentStr, xStart, self.getY(line))
|
||||||
|
elif mode == 'free':
|
||||||
|
freeStr = bytesToStr(free).rjust(5)
|
||||||
|
self.addString(freeStr, xStart, self.getY(line))
|
||||||
|
elif mode == 'bar':
|
||||||
|
percentUsed = (float(total - free) / float(total)) * 100.0
|
||||||
|
self.paintGraph(percentUsed, xStart, self.getY(line) + 2,
|
||||||
|
width - xOffset*2 - xStart - 2)
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Unknown display mode: %s, ignoring data.\n'
|
||||||
|
% mode)
|
||||||
|
def getHdActivity(self):
|
||||||
|
'''Return the current hd activity in percent.
|
||||||
|
|
||||||
|
Return how many percent of the max achieved activity during the
|
||||||
|
program's lifetime the current activity is. However, every time
|
||||||
|
this method is called we decrease the max achieved activity a
|
||||||
|
little bit to get a bit less affected by spikes. I think the
|
||||||
|
interesting thing is to see if the hard drive is active, not
|
||||||
|
really exactly how active.
|
||||||
|
'''
|
||||||
|
statFile = file(self._statFile, 'r')
|
||||||
|
diskIoStartTag = 'disk_io: '
|
||||||
|
ioLine = None
|
||||||
|
for line in statFile:
|
||||||
|
if line.startswith(diskIoStartTag):
|
||||||
|
ioLine = line
|
||||||
|
statFile.close()
|
||||||
|
if ioLine is None:
|
||||||
|
# Can't get HD activity
|
||||||
|
sys.stderr.write("Can't get hd activity from %s\n" %
|
||||||
|
self._statFile)
|
||||||
|
return 0.0
|
||||||
|
ioLine = ioLine[len(diskIoStartTag):]
|
||||||
|
disks = ioLine.split()
|
||||||
|
currIO = 0
|
||||||
|
for disk in disks:
|
||||||
|
dataPart = disk.split(':')[1].strip(')(')
|
||||||
|
infos = dataPart.split(',')
|
||||||
|
blocksRead = long(infos[2])
|
||||||
|
blocksWritten = long(infos[4])
|
||||||
|
currIO += blocksRead + blocksWritten
|
||||||
|
if self._lastIO == -1:
|
||||||
|
self._lastIO = currIO
|
||||||
|
currDiff = currIO - self._lastIO
|
||||||
|
self._lastIO = currIO
|
||||||
|
if currDiff > self._maxIODiff:
|
||||||
|
self._maxIODiff = currDiff
|
||||||
|
if self._maxIODiff <= 0:
|
||||||
|
self._maxIODiff = 0
|
||||||
|
return 0.0
|
||||||
|
currAct = (float(currDiff) / float(self._maxIODiff)) * 100.0
|
||||||
|
self._maxIODiff -= 1 # So spikes won't affect us too much.
|
||||||
|
return currAct
|
||||||
|
|
||||||
|
def updateHdActivity(self):
|
||||||
|
currentAct = self.getHdActivity()
|
||||||
|
self.paintGraph(currentAct, 3, height - yOffset*2 - 3 - graphHeight,
|
||||||
|
width - 2 * xOffset - 6)
|
||||||
|
|
||||||
|
def _checkEvents(self):
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
while not event is None:
|
||||||
|
if event['type'] == 'destroynotify':
|
||||||
|
sys.exit(0)
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
|
||||||
|
def mainLoop(self):
|
||||||
|
counter = -1
|
||||||
|
while 1:
|
||||||
|
counter += 1
|
||||||
|
self._checkEvents()
|
||||||
|
if self._actMonEnabled:
|
||||||
|
self.updateHdActivity()
|
||||||
|
if counter % 100 == 0:
|
||||||
|
index = 0
|
||||||
|
for i in self._pathsToMonitor:
|
||||||
|
if not i is None:
|
||||||
|
label, path, mode = i
|
||||||
|
self.paintLabel(index + 1, label)
|
||||||
|
try:
|
||||||
|
hdData = self.getHdInfo(path)
|
||||||
|
except OSError, e:
|
||||||
|
sys.stderr.write(
|
||||||
|
"Can't get hd data from %s: %s\n" % (path, str(e)))
|
||||||
|
hdData = (0, 0)
|
||||||
|
self.paintHdData(index + 1, hdData, mode)
|
||||||
|
index += 1
|
||||||
|
if counter == 9999999:
|
||||||
|
counter = -1
|
||||||
|
pywmhelpers.redraw()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def parseCommandLine(argv):
|
||||||
|
'''Parse the commandline. Return a dictionary with options and values.'''
|
||||||
|
shorts = 'ht:f:g:b:r:c:p:'
|
||||||
|
longs = ['help', 'textcolor=', 'background=', 'barfgcolor=',
|
||||||
|
'rgbfile=', 'configfile=', 'barbgcolor=', 'procstat=']
|
||||||
|
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 ('-t', '--textcolor'):
|
||||||
|
d['textcolor'] = a
|
||||||
|
if o in ('-b', '--background'):
|
||||||
|
d['background'] = a
|
||||||
|
if o in ('-r', '--rgbfile'):
|
||||||
|
d['rgbfile'] = a
|
||||||
|
if o in ('-c', '--configfile'):
|
||||||
|
d['configfile'] = a
|
||||||
|
if o in ('-g', '--barbgcolor'):
|
||||||
|
d['barbgcolor'] = a
|
||||||
|
if o in ('-f', '--barfgcolor'):
|
||||||
|
d['barfgcolor'] = a
|
||||||
|
if o in ('-p', '--procstat'):
|
||||||
|
d['procstat'] = a
|
||||||
|
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 (<config_key>, <xpm-key>) pairs.
|
||||||
|
colors = (('barfgcolor', 'graph'),
|
||||||
|
('barbgcolor', 'graphbg'),
|
||||||
|
('textcolor', 'text'),
|
||||||
|
('background', 'background'))
|
||||||
|
for key, value in colors:
|
||||||
|
col = config.get(key)
|
||||||
|
if not col is None:
|
||||||
|
code = pywmhelpers.getColorCode(col, rgbFileName)
|
||||||
|
if code is None:
|
||||||
|
sys.stderr.write('Bad colorcode for %s, ignoring.\n' % key)
|
||||||
|
else:
|
||||||
|
pywmhelpers.setColor(xpm, value, code)
|
||||||
|
|
||||||
|
def makeNumDigits(num, numDigits):
|
||||||
|
'''Make a floating point number a certain number of digits, including
|
||||||
|
decimal. Return a string containing it.
|
||||||
|
'''
|
||||||
|
lenOfIntPart = len(str(int(num)))
|
||||||
|
if lenOfIntPart > numDigits:
|
||||||
|
# Can't convert a number to less digits then it's integer part...
|
||||||
|
return ''
|
||||||
|
decimalsNeeded = numDigits - lenOfIntPart
|
||||||
|
s = '%' + str(lenOfIntPart) + '.' + str(decimalsNeeded) + 'f'
|
||||||
|
s = s % round(num, decimalsNeeded)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def bytesToStr(bytes):
|
||||||
|
'''Convert a number of bytes to a nice printable string.
|
||||||
|
|
||||||
|
May raise ValueError if bytes can't be seen as an float.
|
||||||
|
'''
|
||||||
|
bytes = float(bytes)
|
||||||
|
kb = 1024
|
||||||
|
mb = 1024 * 1024
|
||||||
|
gb = 1024 * mb
|
||||||
|
tb = 1024 * gb
|
||||||
|
pb = 1024 * tb
|
||||||
|
if bytes < kb:
|
||||||
|
size = bytes
|
||||||
|
letter = 'B'
|
||||||
|
#return makeNumDigits(bytes, numDigits) + 'B'
|
||||||
|
elif bytes < mb:
|
||||||
|
size = bytes / kb
|
||||||
|
letter = 'k'
|
||||||
|
#return makeNumDigits(bytes/kb, numDigits) + 'k'
|
||||||
|
elif bytes < gb:
|
||||||
|
size = bytes / mb
|
||||||
|
letter = 'M'
|
||||||
|
#return makeNumDigits(bytes/mb, numDigits) + 'M'
|
||||||
|
elif bytes < tb:
|
||||||
|
size = bytes / gb
|
||||||
|
letter = 'G'
|
||||||
|
#return makeNumDigits(bytes/gb, numDigits) + 'G'
|
||||||
|
elif bytes < pb:
|
||||||
|
size = bytes / tb
|
||||||
|
letter = 'T'
|
||||||
|
#return makeNumDigits(bytes/tb, numDigits) + 'T'
|
||||||
|
else:
|
||||||
|
size = bytes / pb
|
||||||
|
letter = 'p'
|
||||||
|
#return makeNumDigits(bytes/pb, numDigits) + 'P'
|
||||||
|
if size >= 1000:
|
||||||
|
res = makeNumDigits(size, 4)
|
||||||
|
else:
|
||||||
|
res = makeNumDigits(size, 3)
|
||||||
|
res += letter
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
clConfig = parseCommandLine(sys.argv)
|
||||||
|
configFile = clConfig.get('configfile', defaultConfigFile)
|
||||||
|
configFile = os.path.expanduser(configFile)
|
||||||
|
fileConfig = pywmhelpers.readConfigFile(configFile, sys.stderr)
|
||||||
|
config = fileConfig
|
||||||
|
for i in clConfig.iteritems():
|
||||||
|
config[i[0]] = i[1]
|
||||||
|
parseColors(defaultRGBFiles, config, xpm)
|
||||||
|
|
||||||
|
pathsToMonitor = []
|
||||||
|
for i in range(1,5):
|
||||||
|
labelStr = str(i) + '.label'
|
||||||
|
pathStr = str(i) + '.path'
|
||||||
|
modeStr = str(i) + '.displaymode'
|
||||||
|
label = config.get(labelStr)
|
||||||
|
path = config.get(pathStr)
|
||||||
|
displayMode = config.get(modeStr, defaultMode)
|
||||||
|
if not displayMode in displayModes:
|
||||||
|
sys.stderr.write(
|
||||||
|
'Unknown display mode: %s, using default.\n' % displayMode)
|
||||||
|
displayMode = defaultMode
|
||||||
|
if label is None or path is None:
|
||||||
|
pathsToMonitor.append(None)
|
||||||
|
else:
|
||||||
|
pathsToMonitor.append((label[:3], path, displayMode))
|
||||||
|
procStat = config.get('procstat', defaultProcStat)
|
||||||
|
actMonEnabled = 1
|
||||||
|
if not os.access(procStat, os.R_OK):
|
||||||
|
sys.stderr.write(
|
||||||
|
"Can't read your procstat file, try setting it with -p. ")
|
||||||
|
sys.stderr.write("Disabling the HD activity bar.\n")
|
||||||
|
actMonEnabled = 0
|
||||||
|
try:
|
||||||
|
programName = sys.argv[0].split(os.sep)[-1]
|
||||||
|
except IndexError:
|
||||||
|
programName = ''
|
||||||
|
sys.argv[0] = programName
|
||||||
|
pywmhelpers.setDefaultPixmap(xpm)
|
||||||
|
pywmhelpers.openXwindow(sys.argv, width, height)
|
||||||
|
# XXX Add commands for clicking different areas?
|
||||||
|
hdmon = PywmHDMon(pathsToMonitor, procStat, actMonEnabled)
|
||||||
|
hdmon.mainLoop()
|
||||||
|
|
||||||
|
|
||||||
|
xpm = \
|
||||||
|
['160 100 13 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',
|
||||||
|
'X\tc #000000000000 s background',
|
||||||
|
'%\tc #2081B2CAAEBA s text',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' ...............................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XXX%XXX%%%%%X%%%%%X%XXX%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%XXXXXXXXXX%XXXXXXXXXX%X%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XX%%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXXX%XXXXXXXXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%%%%%XX%%%%X%%%%%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXXXXXX%XXX%%%%%XXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XXXXXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XX%%XXXX%XXXXXXXXXXXX%XXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XX%%%XX%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XX%%XXXX%XXXXXXXXXXXX%X%XXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'XX%%%XX%%%%XXX%%%%X%%%%XX%%%%XX%%%%%X%%%%%X%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%XXX%X%%%%XX%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%%%%%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%%X%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%X%XXX%X%XXX%XXXXX%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%X%X%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%XX%X%XX%XXX%XXXX%XXXXX',
|
||||||
|
'X%%%%%X%%%%XX%XXXXX%XXX%X%%%%XX%%%%XX%X%%%X%%%%%XXX%XXXXXXX%X%%%XXX%XXXXX%XXX%X%XXX%X%XXX%X%%%%%X%%XX%X%%%%XX%%%%%XXX%XXX%XXX%X%XXX%X%XXX%XXX%XXX%%%%%XXX%XXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%X%X%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%X%X%XX%X%XXXXXX%XX%XXXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXX%XXX%X%XXX%X%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%XX%%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%%X%%X%XXX%XXXXX%X%XXXXXXXX',
|
||||||
|
'X%XXX%X%%%%XXX%%%%X%%%%XX%%%%XX%XXXXX%%%%%X%XXX%XXX%XXXX%%%XX%XXX%X%%%%XX%XXX%X%XXX%X%%%%%X%XXXXX%%%%%X%XXX%X%%%%%XXX%XXXX%%%%XX%%%XX%XXX%X%XXX%X%%%%%X%%%%%XXXX',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................']
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
26
pywmhdmon/sample.pywmhdmon
Normal file
26
pywmhdmon/sample.pywmhdmon
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
# Displaymodes are free, percent or bar, displays the free size, free percent
|
||||||
|
# and a bar representing space, respectively.
|
||||||
|
1.label=/
|
||||||
|
1.path=/
|
||||||
|
1.displaymode=free
|
||||||
|
|
||||||
|
2.label=c
|
||||||
|
2.path=/mnt/c
|
||||||
|
2.displaymode=free
|
||||||
|
|
||||||
|
3.label=d
|
||||||
|
3.path=/mnt/d
|
||||||
|
3.displaymode=free
|
||||||
|
|
||||||
|
4.label=e
|
||||||
|
4.path=/mnt/e
|
||||||
|
4.displaymode=free
|
||||||
|
|
||||||
|
textcolor=light sea green
|
||||||
|
background=black
|
||||||
|
barfgcolor=light sea green
|
||||||
|
barbgcolor=grey45
|
||||||
|
|
||||||
|
#rgbfile=/usr/lib/X11/rgb.txt
|
||||||
|
|
||||||
8
pywmseti/INSTALL
Normal file
8
pywmseti/INSTALL
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
1. If you don't have pywmgeneral installed, install it first. Can be found
|
||||||
|
at http://www.cyd.liu.se/~krier115/pywm/
|
||||||
|
|
||||||
|
2. Copy pywmseti.py to somewhere in your path (like ~/bin or
|
||||||
|
/usr/local/bin).
|
||||||
|
|
||||||
|
3. Copy the sample.pywmseti to ~/.pywmseti and edit as you like.
|
||||||
|
|
||||||
17
pywmseti/README
Normal file
17
pywmseti/README
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[WHAT]
|
||||||
|
Pywmseti is an WindowMaker dockapp for monitoring your seti@home progress.
|
||||||
|
The application displays how many workunits you have done and the progress
|
||||||
|
on the current one. You start/stop the seti@home process by simply clicking
|
||||||
|
anywhere in the application. It also displays the time spent on the workunit
|
||||||
|
(or since you started the program if you restart it in the middle of a
|
||||||
|
workunit). Invoke the program with --help or see the sample rc-file for
|
||||||
|
more information about customization.
|
||||||
|
|
||||||
|
[WHY]
|
||||||
|
No one of the existing monitors suited my needs. And the more Python the
|
||||||
|
world gets, the better it'll be! ;)
|
||||||
|
|
||||||
|
[CONTACT]
|
||||||
|
Mail anything related to this program to me, Kristoffer Erlandsson,
|
||||||
|
<krier115@student.liu.se>
|
||||||
|
|
||||||
551
pywmseti/pywmseti.py
Executable file
551
pywmseti/pywmseti.py
Executable file
@@ -0,0 +1,551 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
'''pywmseti.py
|
||||||
|
|
||||||
|
WindowMaker dockapp to monitor the progress of your seti@home.
|
||||||
|
|
||||||
|
Copyright (C) 2003 Kristoffer Erlandsson
|
||||||
|
|
||||||
|
Licensed under the GNU General Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Changes
|
||||||
|
|
||||||
|
2003-06-24 Kristoffer Erlandsson
|
||||||
|
Added event handling for graceful shutdown
|
||||||
|
|
||||||
|
2003-06-17 Kristoffer Erlandsson
|
||||||
|
First workingish version
|
||||||
|
|
||||||
|
'''
|
||||||
|
usage = '''pywmseti.py [options]
|
||||||
|
Available options are:
|
||||||
|
-h, --help print this help
|
||||||
|
-t, --textcolor <color> set the text color
|
||||||
|
-p, --progressbarcolor <color> set the color of the progress bar
|
||||||
|
-g, --barbgcolor <color> set the background color of the progress bar
|
||||||
|
-i, --indicatorcolor <color> set the color of the running indicator
|
||||||
|
-b, --background <color> set the background color
|
||||||
|
-d, --setidir <directory> set the directory where seti@home resides
|
||||||
|
-n, --nice <value> set the nice value to run seti@home with
|
||||||
|
-r, --rgbfile <file> set the rgb file to get color codes from
|
||||||
|
-c, --configfile <file> set the config file to use
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pywmhelpers
|
||||||
|
|
||||||
|
width = 64
|
||||||
|
height = 64
|
||||||
|
|
||||||
|
xOffset = 4
|
||||||
|
yOffset = 4
|
||||||
|
|
||||||
|
lettersStartX = 0
|
||||||
|
lettersStartY = 74
|
||||||
|
letterWidth = 6
|
||||||
|
letterHeight = 8
|
||||||
|
|
||||||
|
digitsStartX = 0
|
||||||
|
digitsStartY = 64
|
||||||
|
digitWidth = 6
|
||||||
|
digitHeight = 8
|
||||||
|
|
||||||
|
graphStartX = 7
|
||||||
|
graphStartY = 53
|
||||||
|
graphLength = 50
|
||||||
|
graphHeight = 4
|
||||||
|
|
||||||
|
graphBgStartX = 72
|
||||||
|
graphBgStartY = 53
|
||||||
|
|
||||||
|
graphLineStartX = 66
|
||||||
|
graphLineStartY = 58
|
||||||
|
|
||||||
|
runningIndX = 71
|
||||||
|
runningIndY = 1
|
||||||
|
runningIndWidth = 3
|
||||||
|
runningIndHeight = 15
|
||||||
|
numRunningInds = 4
|
||||||
|
|
||||||
|
letters = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
|
digits = '0123456789:/-% '
|
||||||
|
|
||||||
|
defaultConfigFile = '~/.pywmsetirc'
|
||||||
|
defaultRGBFiles = ['/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt']
|
||||||
|
|
||||||
|
stateFileName = 'state.sah'
|
||||||
|
uinfoFileName = 'user_info.sah'
|
||||||
|
pidFileName = 'pid.sah'
|
||||||
|
execFileName = 'setiathome'
|
||||||
|
|
||||||
|
class PywmSeti:
|
||||||
|
def __init__(self, statePath, uinfoPath, pidPath, execCmd):
|
||||||
|
self._statePath = statePath
|
||||||
|
self._uinfoPath = uinfoPath
|
||||||
|
self._pidPath = pidPath
|
||||||
|
self._execCmd = execCmd
|
||||||
|
self._currentRunningInd = 0
|
||||||
|
self._lastTime = time.time()
|
||||||
|
self._lastNumResults = -1
|
||||||
|
self._progress = 0
|
||||||
|
|
||||||
|
def addString(self, s, x, y):
|
||||||
|
try:
|
||||||
|
pywmhelpers.addString(s, x, y, letterWidth, letterHeight,
|
||||||
|
lettersStartX, lettersStartY, letters, digitWidth,
|
||||||
|
digitHeight, digitsStartX, digitsStartY, digits,
|
||||||
|
xOffset, yOffset, width, height)
|
||||||
|
except ValueError, e:
|
||||||
|
sys.stderr.write('Error when painting string:\n' + str(e) + '\n')
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
def getCenterStartPos(self, s):
|
||||||
|
return pywmhelpers.getCenterStartPos(s, letterWidth, width, xOffset)
|
||||||
|
|
||||||
|
def getVertSpacing(self, numLines, margin):
|
||||||
|
return pywmhelpers.getVertSpacing(numLines, margin, height,
|
||||||
|
letterHeight, yOffset)
|
||||||
|
|
||||||
|
def getProgress(self, lines):
|
||||||
|
'''Return the progess of the current workunit.
|
||||||
|
|
||||||
|
Supply the lines of the statefile as argument.
|
||||||
|
'''
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith('prog='):
|
||||||
|
try:
|
||||||
|
progress = float(line.split('=')[-1])
|
||||||
|
except ValueError:
|
||||||
|
progress = 0
|
||||||
|
return progress
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getNumResults(self, lines):
|
||||||
|
'''Return the number of results produced.
|
||||||
|
|
||||||
|
Supply the lines in the user info file as argument.
|
||||||
|
'''
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith('nresults='):
|
||||||
|
try:
|
||||||
|
results = int(line.split('=')[-1])
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return results
|
||||||
|
sys.stderr.write(
|
||||||
|
"Error when reading uinfo file! Can't get number of results.\n")
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def pidIsRunning(self, pid):
|
||||||
|
'''Determine if the process with PID pid is running.
|
||||||
|
|
||||||
|
Return 1 if it is running.
|
||||||
|
Return 0 if it is not running.
|
||||||
|
Return -1 if we do not have permission to signal the process
|
||||||
|
This could be slightly non-portal, but I can not find any better
|
||||||
|
way to do it.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
os.kill(pid, 0)
|
||||||
|
except OSError, e:
|
||||||
|
if e.errno == 1:
|
||||||
|
return -1
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def openFileRead(self, fileName):
|
||||||
|
try:
|
||||||
|
f = file(fileName, 'r')
|
||||||
|
except IOError, e:
|
||||||
|
sys.stderr.write('Error when opening %s: %s\n' % (fileName, str(e)))
|
||||||
|
return None
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def paintCurrentRunningIndicator(self):
|
||||||
|
'''Paint the running indicator.
|
||||||
|
'''
|
||||||
|
indX = runningIndX + self._currentRunningInd * \
|
||||||
|
(runningIndWidth + 2)
|
||||||
|
indY = runningIndY
|
||||||
|
w = runningIndWidth
|
||||||
|
h = runningIndHeight
|
||||||
|
targX = width - xOffset - w - 5
|
||||||
|
targY = yOffset + 5
|
||||||
|
pywmhelpers.copyXPMArea(indX, indY, w, h, targX, targY)
|
||||||
|
|
||||||
|
def updateRunning(self):
|
||||||
|
'''Update the information regarding if we got seti@home running or not.
|
||||||
|
|
||||||
|
Return a tuple with (running, startStopenabled).
|
||||||
|
startStopEnabled is 1 if we own the process and got the permissions
|
||||||
|
to start and stop it, or if there is no process running.
|
||||||
|
'''
|
||||||
|
pidFile = self.openFileRead(self._pidPath)
|
||||||
|
if pidFile is None:
|
||||||
|
sys.stderr.write("Can't read pid file")
|
||||||
|
self._running = 0
|
||||||
|
self._startStopEnabled = 0
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self._pid = int(pidFile.read().strip())
|
||||||
|
except ValueError:
|
||||||
|
sys.stderr.write("Can't get pid from %s.\n" % self._pidPath)
|
||||||
|
self._running = 0
|
||||||
|
self._startStopEnabled = 0
|
||||||
|
return
|
||||||
|
pidFile.close()
|
||||||
|
self._running = self.pidIsRunning(self._pid)
|
||||||
|
if self._running == -1 and self._startStopEnabled:
|
||||||
|
sys.stderr.write(
|
||||||
|
"An other seti@home process which you don't own is running.\n")
|
||||||
|
sys.stderr.write(
|
||||||
|
"Starting and stopping of the process is disabled.\n")
|
||||||
|
self._startStopenabled = 0
|
||||||
|
if self._running == -1:
|
||||||
|
self._running = 1
|
||||||
|
else:
|
||||||
|
# If no process is running (we could have stopped the one
|
||||||
|
# running from an other process), enable starting and stopping.
|
||||||
|
self._startStopEnabled = 1
|
||||||
|
if self._running:
|
||||||
|
self._currentRunningInd = (self._currentRunningInd - 1) \
|
||||||
|
% numRunningInds
|
||||||
|
else:
|
||||||
|
self._currentRunningInd = 0
|
||||||
|
self.paintCurrentRunningIndicator()
|
||||||
|
|
||||||
|
def updateProgress(self):
|
||||||
|
'''Update the progress on the current workunit.'''
|
||||||
|
stateFile = self.openFileRead(self._statePath)
|
||||||
|
if stateFile is None:
|
||||||
|
# Can't open file, probably in progress of gettin a new workunit.
|
||||||
|
progress = 0
|
||||||
|
else:
|
||||||
|
progress = self.getProgress(stateFile.readlines())
|
||||||
|
stateFile.close()
|
||||||
|
self._progress = progress
|
||||||
|
percent = int(progress * 100.0)
|
||||||
|
graphSize = int(round(progress * graphLength))
|
||||||
|
pywmhelpers.copyXPMArea(
|
||||||
|
graphLineStartX, graphLineStartY, graphSize, graphHeight,
|
||||||
|
graphStartX, graphStartY)
|
||||||
|
pywmhelpers.copyXPMArea(
|
||||||
|
graphBgStartX, graphBgStartY, graphLength - graphSize, graphHeight,
|
||||||
|
graphStartX + graphSize, graphStartY)
|
||||||
|
self.addString((str(percent) + '%').ljust(4), 4, 32)
|
||||||
|
|
||||||
|
def updateNumResults(self):
|
||||||
|
'''Update the number of workunits done.'''
|
||||||
|
uinfoFile = self.openFileRead(self._uinfoPath)
|
||||||
|
numResults = self.getNumResults(uinfoFile.readlines())
|
||||||
|
if self._lastNumResults == -1:
|
||||||
|
self._lastNumResults = numResults
|
||||||
|
if numResults != self._lastNumResults and self._progress < 0.03:
|
||||||
|
# If we just got a new number of results and the progress of the
|
||||||
|
# current workunit is under 3%, assume we started working on a new
|
||||||
|
# workunit. The times this could be missleading is if we have an
|
||||||
|
# other seti@home process running on an other computer, but this is
|
||||||
|
# accurate enough I think.
|
||||||
|
self.nextWorkUnitStarted()
|
||||||
|
self._lastNumResults = numResults
|
||||||
|
uinfoFile.close()
|
||||||
|
self.addString(str(numResults)[:7], 4, 4)
|
||||||
|
|
||||||
|
def updateTime(self):
|
||||||
|
'''Update the time line.
|
||||||
|
|
||||||
|
We display the time that we have been on the current work unit, since
|
||||||
|
either the last one was done or since we started the program.
|
||||||
|
'''
|
||||||
|
timeSpent = time.time() - self._lastTime
|
||||||
|
hours = int(timeSpent / 3600)
|
||||||
|
mins = int((timeSpent - hours * 3600) / 60)
|
||||||
|
hours = str(hours)[:3]
|
||||||
|
mins = str(mins).zfill(2)
|
||||||
|
s = (hours + ':' + mins).ljust(6)
|
||||||
|
self.addString(s, 4, 18)
|
||||||
|
|
||||||
|
def nextWorkUnitStarted(self):
|
||||||
|
self._lastTime = time.time()
|
||||||
|
|
||||||
|
def handleMouseClick(self, region):
|
||||||
|
if region == 0:
|
||||||
|
if self._startStopEnabled:
|
||||||
|
if self._running:
|
||||||
|
try:
|
||||||
|
os.kill(self._pid, 15)
|
||||||
|
except OSError, e:
|
||||||
|
sys.stderr.write(
|
||||||
|
"Error when ending process: "+str(e)+'\n')
|
||||||
|
else:
|
||||||
|
os.system(self._execCmd) # Use fork instead?
|
||||||
|
|
||||||
|
def _checkForEvents(self):
|
||||||
|
'''Check for, and handle, X events.'''
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
while not event is None:
|
||||||
|
if event['type'] == 'buttonrelease':
|
||||||
|
region = pywmhelpers.checkMouseRegion(event['x'],
|
||||||
|
event['y'])
|
||||||
|
self.handleMouseClick(region)
|
||||||
|
elif event['type'] == 'destroynotify':
|
||||||
|
sys.exit(0)
|
||||||
|
event = pywmhelpers.getEvent()
|
||||||
|
|
||||||
|
def mainLoop(self):
|
||||||
|
counter = -1
|
||||||
|
self._startStopEnabled = 1
|
||||||
|
while 1:
|
||||||
|
counter += 1
|
||||||
|
self._checkForEvents()
|
||||||
|
if counter % 10 == 0:
|
||||||
|
self.updateRunning()
|
||||||
|
if counter % 100 == 0:
|
||||||
|
self.updateProgress()
|
||||||
|
self.updateNumResults()
|
||||||
|
self.updateTime()
|
||||||
|
if counter == 999999:
|
||||||
|
counter = -1
|
||||||
|
pywmhelpers.redraw()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def parseCommandLine(argv):
|
||||||
|
'''Parse the commandline. Return a dictionary with options and values.'''
|
||||||
|
shorts = 'ht:b:n:d:r:c:p:g:i:'
|
||||||
|
longs = ['help', 'textcolor=', 'background=', 'setidir=', 'nice=',
|
||||||
|
'rgbfile=', 'configfile=', 'progressbarcolor=', 'barbgcolor=',
|
||||||
|
'indicatorcolor=']
|
||||||
|
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 ('-t', '--textcolor'):
|
||||||
|
d['textcolor'] = a
|
||||||
|
if o in ('-b', '--background'):
|
||||||
|
d['background'] = a
|
||||||
|
if o in ('-d', '--setidir'):
|
||||||
|
d['setidir'] = a
|
||||||
|
if o in ('-n', '--nice'):
|
||||||
|
d['nice'] = a
|
||||||
|
if o in ('-r', '--rgbfile'):
|
||||||
|
d['rgbfile'] = a
|
||||||
|
if o in ('-c', '--configfile'):
|
||||||
|
d['configfile'] = a
|
||||||
|
if o in ('-p', '--progressbarcolor'):
|
||||||
|
d['progressbarcolor'] = a
|
||||||
|
if o in ('-g', '--barbgcolor'):
|
||||||
|
d['barbgcolor'] = a
|
||||||
|
if o in ('-i', '--indicatorcolor'):
|
||||||
|
d['indicatorcolor'] = a
|
||||||
|
return d
|
||||||
|
|
||||||
|
def parseColors(defaultRGBFileNames, config, xpm):
|
||||||
|
rgbFileName = ''
|
||||||
|
for fn in defaultRGBFileNames:
|
||||||
|
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 (<config_key>, <xpm-key>) pairs.
|
||||||
|
colors = (('indicatorcolor', 'indicator'),
|
||||||
|
('progressbarcolor', 'graph'),
|
||||||
|
('barbgcolor', 'graphbg'),
|
||||||
|
('textcolor', 'text'),
|
||||||
|
('background', 'background'))
|
||||||
|
for key, value in colors:
|
||||||
|
col = config.get(key)
|
||||||
|
if not col is None:
|
||||||
|
code = pywmhelpers.getColorCode(col, rgbFileName)
|
||||||
|
if code is None:
|
||||||
|
sys.stderr.write('Bad colorcode for %s, ignoring.\n' % key)
|
||||||
|
else:
|
||||||
|
pywmhelpers.setColor(xpm, value, code)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
clConfig = parseCommandLine(sys.argv)
|
||||||
|
configFile = clConfig.get('configfile', defaultConfigFile)
|
||||||
|
configFile = os.path.expanduser(configFile)
|
||||||
|
fileConfig = pywmhelpers.readConfigFile(configFile, sys.stderr)
|
||||||
|
# Merge the two configs, let the commandline options overwrite those in the
|
||||||
|
# configuration file.
|
||||||
|
config = fileConfig
|
||||||
|
for i in clConfig.iteritems():
|
||||||
|
config[i[0]] = i[1]
|
||||||
|
# Get the configurations
|
||||||
|
parseColors(defaultRGBFiles, config, xpm)
|
||||||
|
setiDir = config.get('setidir')
|
||||||
|
if setiDir is None:
|
||||||
|
sys.stderr.write(
|
||||||
|
'You have to supply a directory where seti@home resides. Either in\n')
|
||||||
|
sys.stderr.write(
|
||||||
|
'the configuration file or with -d/--setidir.\n')
|
||||||
|
sys.exit(3)
|
||||||
|
setiDir = os.path.expanduser(setiDir)
|
||||||
|
try:
|
||||||
|
os.chdir(setiDir)
|
||||||
|
except OSError, e:
|
||||||
|
sys.stderr.write('Error when accessing seti directory: %s\n' % str(e))
|
||||||
|
sys.exit(4)
|
||||||
|
statePath = os.path.join(setiDir, stateFileName)
|
||||||
|
uinfoPath = os.path.join(setiDir, uinfoFileName)
|
||||||
|
pidPath = os.path.join(setiDir, pidFileName)
|
||||||
|
execPath = os.path.join(setiDir, execFileName)
|
||||||
|
niceVal = config.get('nice')
|
||||||
|
if niceVal is None:
|
||||||
|
execCmd = execPath
|
||||||
|
else:
|
||||||
|
execCmd = execPath + ' -nice %s' % niceVal + '&'
|
||||||
|
try:
|
||||||
|
programName = sys.argv[0].split(os.sep)[-1]
|
||||||
|
except IndexError:
|
||||||
|
programName = ''
|
||||||
|
sys.argv[0] = programName
|
||||||
|
pywmhelpers.setDefaultPixmap(xpm)
|
||||||
|
pywmhelpers.openXwindow(sys.argv, width, height)
|
||||||
|
pywmhelpers.addMouseRegion(0, xOffset, yOffset, width - 2 * xOffset,
|
||||||
|
height - 2 * yOffset)
|
||||||
|
pwms = PywmSeti(statePath, uinfoPath, pidPath, execCmd)
|
||||||
|
pwms.mainLoop()
|
||||||
|
|
||||||
|
xpm = \
|
||||||
|
['160 100 13 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',
|
||||||
|
'X\tc #000000000000 s background',
|
||||||
|
'%\tc #2081B2CAAEBA s text',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo.......................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' ...............................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XXX%XXX%%%%%X%%%%%X%XXX%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%XXXXXXXXXX%XXXXXXXXXX%X%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XX%%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXXX%XXXXXXXXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%%%%%XX%%%%X%%%%%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXXXXXX%XXX%%%%%XXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XXXXXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XX%%XXXX%XXXXXXXXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XX%%%XX%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XX%%XXXX%XXXXXXXXXXXX%X%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'XX%%%XX%%%%XXX%%%%X%%%%XX%%%%XX%%%%%X%%%%%X%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%XXX%X%%%%XX%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%%%%%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%%X%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%X%XXX%X%XXX%XXXXX%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%X%X%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%XX%X%XX%XXX%XXXX%XXXXX',
|
||||||
|
'X%%%%%X%%%%XX%XXXXX%XXX%X%%%%XX%%%%XX%X%%%X%%%%%XXX%XXXXXXX%X%%%XXX%XXXXX%XXX%X%XXX%X%XXX%X%%%%%X%%XX%X%%%%XX%%%%%XXX%XXX%XXX%X%XXX%X%XXX%XXX%XXX%%%%%XXX%XXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%X%X%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%X%X%XX%X%XXXXXX%XX%XXXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXX%XXX%X%XXX%X%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%XX%%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%%X%%X%XXX%XXXXX%X%XXXXXXXX',
|
||||||
|
'X%XXX%X%%%%XXX%%%%X%%%%XX%%%%XX%XXXXX%%%%%X%XXX%XXX%XXXX%%%XX%XXX%X%%%%XX%XXX%X%XXX%X%%%%%X%XXXXX%%%%%X%XXX%X%%%%%XXX%XXXX%%%%XX%%%XX%XXX%X%XXX%X%%%%%X%%%%%XXXX',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................']
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
12
pywmseti/sample.pywmsetirc
Normal file
12
pywmseti/sample.pywmsetirc
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
setidir=/home/erl/setiathome
|
||||||
|
# Nice value to start the seti@home process with on click.
|
||||||
|
nice=19
|
||||||
|
textcolor=light sea green
|
||||||
|
progressbarcolor=light sea green
|
||||||
|
barbgcolor=grey45
|
||||||
|
indicatorcolor=light sea green
|
||||||
|
background=black
|
||||||
|
|
||||||
|
#rgbfile=/usr/lib/X11/rgb.txt
|
||||||
|
|
||||||
6
pywmsysmon/INSTALL
Normal file
6
pywmsysmon/INSTALL
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
1. If you don't have pywmgeneral installed, install it first. Can be found
|
||||||
|
at http://foo.unix.se/pywmdockapps
|
||||||
|
|
||||||
|
2. Copy pywmsysmon.py to somewhere in your path (like ~/bin or
|
||||||
|
/usr/local/bin).
|
||||||
|
|
||||||
15
pywmsysmon/README
Normal file
15
pywmsysmon/README
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[WHAT]
|
||||||
|
pywmsysmon is a WindowMaker dockapp that displays your cpu and memory
|
||||||
|
usages. The upper graph shows your cpu usage history and the lower
|
||||||
|
"progress bar" shows your current memory usage excluding cached and
|
||||||
|
buffered data. This program currently only works on systems which got
|
||||||
|
the /proc/stat and /proc/meminfo files available. Invoke the program
|
||||||
|
with --help for information about customization.
|
||||||
|
|
||||||
|
[WHY]
|
||||||
|
As usual, I didn't find a dockapp that fitted me.
|
||||||
|
|
||||||
|
[CONTACT]
|
||||||
|
Mail anything related to this program to me, Kristoffer Erlandsson,
|
||||||
|
<krier115@student.liu.se>
|
||||||
|
|
||||||
465
pywmsysmon/pywmsysmon.py
Executable file
465
pywmsysmon/pywmsysmon.py
Executable file
@@ -0,0 +1,465 @@
|
|||||||
|
#! /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 pywmhelpers
|
||||||
|
|
||||||
|
width = 64
|
||||||
|
height = 64
|
||||||
|
|
||||||
|
xOffset = 4
|
||||||
|
yOffset = 4
|
||||||
|
|
||||||
|
lettersStartX = 0
|
||||||
|
lettersStartY = 74
|
||||||
|
letterWidth = 6
|
||||||
|
letterHeight = 8
|
||||||
|
|
||||||
|
digitsStartX = 0
|
||||||
|
digitsStartY = 64
|
||||||
|
digitWidth = 6
|
||||||
|
digitHeight = 8
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
letters = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
|
digits = '0123456789:/-%. '
|
||||||
|
|
||||||
|
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)
|
||||||
|
theLine = None
|
||||||
|
for line in meminfoFile:
|
||||||
|
if line.startswith('Mem:'):
|
||||||
|
theLine = line
|
||||||
|
if theLine is None:
|
||||||
|
sys.stderr.write("Can't find memory information in %s.\n" %
|
||||||
|
self._procMeminfo)
|
||||||
|
sys.exit(4)
|
||||||
|
parts = [long(x) for x in theLine.split()[1:]]
|
||||||
|
total, used, free, shared, buffers, cached = parts
|
||||||
|
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:]]
|
||||||
|
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:
|
||||||
|
pywmhelpers.addString(s, x, y, letterWidth, letterHeight,
|
||||||
|
lettersStartX, lettersStartY, letters, digitWidth,
|
||||||
|
digitHeight, digitsStartX, digitsStartY, 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:
|
||||||
|
pywmhelpers.copyXPMArea(
|
||||||
|
hGraphLineStartX, hGraphLineStartY, paintWidth, hGraphHeight,
|
||||||
|
x, y)
|
||||||
|
if w - paintWidth > 0:
|
||||||
|
pywmhelpers.copyXPMArea(
|
||||||
|
hGraphBgStartX, hGraphBgStartY, w - paintWidth, hGraphHeight,
|
||||||
|
x + paintWidth, y)
|
||||||
|
|
||||||
|
def drawVertLine(self, sourceX, sourceY, targX, targY, length):
|
||||||
|
'''Draw a vertical line.
|
||||||
|
'''
|
||||||
|
if length > 0:
|
||||||
|
pywmhelpers.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 = pywmhelpers.getEvent()
|
||||||
|
while not event is None:
|
||||||
|
if event['type'] == 'destroynotify':
|
||||||
|
sys.exit(0)
|
||||||
|
event = pywmhelpers.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
|
||||||
|
pywmhelpers.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 (<config_key>, <xpm-key>) 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 = pywmhelpers.getColorCode(col, rgbFileName)
|
||||||
|
if code is None:
|
||||||
|
sys.stderr.write('Bad colorcode for %s, ignoring.\n' % key)
|
||||||
|
else:
|
||||||
|
pywmhelpers.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
|
||||||
|
pywmhelpers.setDefaultPixmap(xpm)
|
||||||
|
pywmhelpers.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',
|
||||||
|
'X\tc #000000000000 s background',
|
||||||
|
'%\tc #2081B2CAAEBA s text',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX......|.I..............................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX......|.I..............................................................',
|
||||||
|
' .///..XXX..ooo..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..ooo..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..XXX......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..XXX..XXX..XXX..ooo......|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///..........................|.I..............................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...-------------------------------------------------------------------------------------...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///...........................................................................................',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' .///////////////////////////////////////////////////////////////////////////////////////////...',
|
||||||
|
' ...............................................................................................',
|
||||||
|
' ...............................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XXX%XXX%%%%%X%%%%%X%XXX%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%XXXXXXXXXX%XXXXXXXXXX%X%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XX%%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXXX%XXXXXXXXXXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXXXXXX%XXXXX%X%XXX%X%XXXXX%XXXXXXXXX%X%XXX%X%XXX%XX%%XXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%%%%%XX%%%%X%%%%%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXXXXXX%XXX%%%%%XXXX%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XXXXXXXX%%XXXXXXXXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%XXX%XXX%XXX%XXXXXXXXX%XXXXX%XXXXX%X%XXX%XXXXX%X%XXX%XXXXX%XX%%XXXX%XXXXXXXXXXXX%XXXXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'X%%%%%XX%%%XX%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XXXXX%X%%%%%X%%%%%XX%%XXXX%XXXXXXXXXXXX%X%XXX%%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'XX%%%XX%%%%XXX%%%%X%%%%XX%%%%XX%%%%%X%%%%%X%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%XXX%X%%%%XX%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%%%%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%%%%%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XXX%X%XXXXX%%X%%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%X%XXX%X%XXX%XXXXX%XXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXXXX%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%X%X%X%XXX%X%XXX%X%XXX%X%XXX%X%XXX%X%XXXXXXX%XXX%XXX%X%XXX%X%XXX%XX%X%XX%XXX%XXXX%XXXXX',
|
||||||
|
'X%%%%%X%%%%XX%XXXXX%XXX%X%%%%XX%%%%XX%X%%%X%%%%%XXX%XXXXXXX%X%%%XXX%XXXXX%XXX%X%XXX%X%XXX%X%%%%%X%%XX%X%%%%XX%%%%%XXX%XXX%XXX%X%XXX%X%XXX%XXX%XXX%%%%%XXX%XXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXXXXXX%X%XX%XX%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%X%X%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%X%X%XX%X%XXXXXX%XX%XXXXXXX',
|
||||||
|
'X%XXX%X%XXX%X%XXXXX%XXX%X%XXXXX%XXXXX%XXX%X%XXX%XXX%XXX%XXX%X%XXX%X%XXXXX%XXX%X%XXX%X%XXX%X%XXXXX%XX%%X%XXX%XXXXX%XXX%XXX%XXX%X%XXX%X%%X%%X%XXX%XXXXX%X%XXXXXXXX',
|
||||||
|
'X%XXX%X%%%%XXX%%%%X%%%%XX%%%%XX%XXXXX%%%%%X%XXX%XXX%XXXX%%%XX%XXX%X%%%%XX%XXX%X%XXX%X%%%%%X%XXXXX%%%%%X%XXX%X%%%%%XXX%XXXX%%%%XX%%%XX%XXX%X%XXX%X%%%%%X%%%%%XXXX',
|
||||||
|
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................',
|
||||||
|
'................................................................................................................................................................']
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user