From 9c81d722a7051aec012ec8c4af30cada0166e9fe Mon Sep 17 00:00:00 2001 From: mfrasca <> Date: Tue, 3 Oct 2006 07:45:21 +0000 Subject: [PATCH] 1569327 release 1.1 is broken trying to clean up things. wmdocklib now contains the modules to install. examples all the scripts. only pywmhdmon.py has been tested. --- MANIFEST | 30 +- README.txt | 29 +- {pywmdatetime => examples}/pywmdatetime.py | 0 examples/pywmgeneric.py | 747 ++++++++++++++++++ examples/pywmhdmon.py | 589 ++++++++++++++ examples/pywmseti.py | 551 +++++++++++++ examples/pywmsysmon.py | 465 +++++++++++ .../sample.pywmdatetimerc | 0 examples/sample.pywmgenericrc | 69 ++ examples/sample.pywmhdmonrc | 50 ++ examples/sample.pywmsetirc | 12 + examples/tmount | 35 + pywmdatetime/INSTALL | 8 - pywmdatetime/README | 14 - pywmdatetime/__init__.py | 1 - pywmgeneral/INSTALL | 10 - pywmgeneral/PKG-INFO | 10 - pywmgeneral/README | 23 - pywmgeneral/__init__.py | 1 - pywmgeneral/pywmgeneral.c | 596 -------------- pywmgeneral/pywmgeneral.h | 66 -- pywmgeneral/pywmhelpers.py | 253 ------ pywmgeneral/setup.py | 26 - pywmgeneric/ChangeLog | 8 - pywmgeneric/INSTALL | 13 - pywmgeneric/README | 69 -- 26 files changed, 2547 insertions(+), 1128 deletions(-) rename {pywmdatetime => examples}/pywmdatetime.py (100%) create mode 100644 examples/pywmgeneric.py create mode 100755 examples/pywmhdmon.py create mode 100755 examples/pywmseti.py create mode 100755 examples/pywmsysmon.py rename {pywmdatetime => examples}/sample.pywmdatetimerc (100%) create mode 100644 examples/sample.pywmgenericrc create mode 100644 examples/sample.pywmhdmonrc create mode 100644 examples/sample.pywmsetirc create mode 100644 examples/tmount delete mode 100644 pywmdatetime/INSTALL delete mode 100644 pywmdatetime/README delete mode 100644 pywmdatetime/__init__.py delete mode 100644 pywmgeneral/INSTALL delete mode 100644 pywmgeneral/PKG-INFO delete mode 100644 pywmgeneral/README delete mode 100644 pywmgeneral/__init__.py delete mode 100644 pywmgeneral/pywmgeneral.c delete mode 100644 pywmgeneral/pywmgeneral.h delete mode 100644 pywmgeneral/pywmhelpers.py delete mode 100755 pywmgeneral/setup.py delete mode 100644 pywmgeneric/ChangeLog delete mode 100644 pywmgeneric/INSTALL delete mode 100644 pywmgeneric/README diff --git a/MANIFEST b/MANIFEST index 245694d..3c88525 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,21 +1,19 @@ README.txt setup.py -pywmdatetime/__init__.py -pywmdatetime/pywmdatetime.py -pywmdatetime/sample.pywmdatetimerc +examples/pywmdatetime.py +examples/pywmhdmon.py +examples/pywmseti.py +examples/pywmsysmon.py +examples/sample.pywmdatetimerc +examples/sample.pywmgenericrc +examples/sample.pywmhdmonrc +examples/sample.pywmsetirc +examples/setup.py pywmgeneral/__init__.py -pywmgeneral/pywmgeneral.c -pywmgeneral/pywmgeneral.h pywmgeneral/pywmhelpers.py pywmgeneral/setup.py -pywmgeneric/__init__.py -pywmgeneric/pywmgeneric.py -pywmgeneric/sample.pywmgenericrc -pywmhdmon/__init__.py -pywmhdmon/pywmhdmon.py -pywmhdmon/sample.pywmhdmonrc -pywmseti/__init__.py -pywmseti/pywmseti.py -pywmseti/sample.pywmsetirc -pywmsysmon/__init__.py -pywmsysmon/pywmsysmon.py +wmdocklib/__init__.py +wmdocklib/pywmgeneral.c +wmdocklib/pywmgeneral.h +wmdocklib/pywmgeneric.py +wmdocklib/pywmhelpers.py diff --git a/README.txt b/README.txt index d3fdbd2..bedb901 100644 --- a/README.txt +++ b/README.txt @@ -1,20 +1,21 @@ [WHAT] -pywmdockapps is a small suite of python modules that will help you develop -WindowMaker dockapps in python. pywmgeneral.py, the central module of the -suite, is mostly a wrapper around the functions from the popular -wmgeneral.c, but some new functions are added too. +pywmdockapps is the name of an GPL'd project containing one python package +(wmdocklib) and a few python scripts. wmdocklib will help you develop +WindowMaker dockapps in python. it is mostly a wrapper around the popular +wmgeneral.c, but some new functions have been added too. -the suite 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)'. +wmdocklib is divided in two parts: a thin wrapper around the popular +wmgeneral.c and a thicker pywmhelpers.py module providing more pythonic +interface to the wmdocklib and a few additional functions (e.g.: handling +simple configuration files). all functions provided by these modules are +imported in the namespace of wmdocklib so you won't need explicit importing +of either modules: just import wmdocklib. It is adviced to only use those +functions provided by 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)'. +the sample scripts are described in the examples/README a small set of samples are provided. all of them make use of the module pywmgeneral. diff --git a/pywmdatetime/pywmdatetime.py b/examples/pywmdatetime.py similarity index 100% rename from pywmdatetime/pywmdatetime.py rename to examples/pywmdatetime.py diff --git a/examples/pywmgeneric.py b/examples/pywmgeneric.py new file mode 100644 index 0000000..b3ba74c --- /dev/null +++ b/examples/pywmgeneric.py @@ -0,0 +1,747 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +'''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 set the text color + -b, --background set the background color + -r, --rgbfile set the rgb file to get color codes from + -c, --configfile set the config file to use +''' + +import sys +import os +import time +import string +import ConfigParser +import getopt +import popen2 + +from pywmgeneral import pywmhelpers + +prevStat = {'user':0, + 'nice':0, + 'sys':0, + 'idle':0, + 'total':0, + } +import re +cpuinfo = re.compile(r'^cpu[^ ]* +(?P[0-9]+) +(?P[0-9]+)' + r'+(?P[0-9]+) +(?P[0-9]+)') + +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 ALREADY HERE ARE JUST SAMPLES AND WILL PROBABLY NOT WORK + WITH YOUR SYSTEM. + """ + + userTicks = sysTicks = niceTicks = idleTicks = 0 + + def getCpuTemp(self): + def result(): + global prevStat + try: + f = file('/proc/stat', 'r') + except IOError: + return 'error' + + currStat = dict( + [(k, int(v)) + for (k,v) in cpuinfo.match(f.readline()).groupdict().items()] + ) + f.close() + + total = 0 + for k,v in currStat.items(): + total += v + currStat['total'] = total + totalTicks = (currStat['total'] - prevStat['total']) + + result = {} + if (totalTicks <= 0): + return '00/00/00' + + for k in prevStat: + result[k] = (100. * (currStat[k] - prevStat[k])) / totalTicks + prevStat = currStat + + return '%(user)02.f/%(sys)02.f/%(idle)02.f' % result + return result + + 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/share/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 (, ). + + 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 = 'aeiouaeiouaeiouaeiou' + 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 % 2 == 0: + [e.tick1() for e in self._entrys if not e is None] + if counter % 20 == 0: + [e.tick2() for e in self._entrys if not e is None] + + if counter == 999999: + counter = -1 + pywmhelpers.redraw() + time.sleep(0.5) + +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 (, ) 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) + if not configFile.count(os.sep): + configFile = os.sep.join(sys.argv[0].split(os.sep)[:-1]) + os.sep + configFile + 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() diff --git a/examples/pywmhdmon.py b/examples/pywmhdmon.py new file mode 100755 index 0000000..eb87123 --- /dev/null +++ b/examples/pywmhdmon.py @@ -0,0 +1,589 @@ +#!/usr/bin/env python2.3 + +"""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 + +2005-09-02 Mario Frasca + added -s option for skipping an amount of configuration items. + changed some single quotes to double quotes for use in emacs. + updated the rc sample file + +2004-07-16 Mario Frasca + recognizes unmounted partitions. + configurable mouse actions. + 'used' information for read-only media. + recognizes #-started numerical-coded colors. + +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 set the text color +-f, --barfgcolor set the foregroundcolor of the act. bar +-g, --barbgcolor set the background color of the act. bar +-b, --background set the background color +-r, --rgbfile set the rgb file to get color codes from +-c, --configfile set the config file to use +-p, --procstat set the location of /proc/stat +-s, --skipconf determines how many configuration items to skip +''' + +import sys +import time +import getopt +import os + +import wmdocklib + +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 = os.environ['HOME']+'/.pywmhdmonrc' +defaultRGBFiles = ('/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt') +defaultProcStat = '/proc/stat' +displayModes = ('bar', 'percent', 'free', 'used') +defaultMode = 'bar' + +hdmon = None + +class NotMounted(OSError): + pass + +class PywmHDMon: + def __init__(self, pathsToMonitor, procStat='/proc/stat', actMonEnabled=1, skipping=0): + self._pathsToMonitor = pathsToMonitor + self._actMonEnabled = actMonEnabled + self._skipping = skipping + + self._statFile = procStat + self._maxIODiff = 0 + self._lastIO = -1 + + def addString(self, s, x, y): + try: + wmdocklib.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 (, ) in bytes. Raise + OSError if we can't stat the path. Raise NotMounted if not mounted. + These operations are quite costly, not adviced to perform these checks + more than once every 10 seconds. + """ + + # check if is mounted <- st_dev(/mount/point) == st_dev(/mount) + if path is not '/': + statOwn = os.stat(path) + + # the following is a bit ugly: it removes the trailing + # dirname from the mount point. split by '/', leave the + # last string, join back, check for empty string. + statCnt = os.stat('/'.join(path.split('/')[:-1]) or '/') + if statOwn[2] == statCnt[2]: + raise NotMounted + 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, thin=None): + '''Paint a graph with percentFilled percent filled. + + Paint at position x, y and with width w. + if thin == 1, make it a thin line instead of a block. + ''' + paintWidth = int(round(percentFilled/100.0 * w)) + if paintWidth > 0: + wmdocklib.copyXPMArea( + graphLineStartX, graphLineStartY, paintWidth, thin or graphHeight, + x + xOffset, y + yOffset) + if w - paintWidth > 0: + wmdocklib.copyXPMArea( + graphBgStartX, graphBgStartY, w - paintWidth, thin or 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 total==0: + self.addString(' ', xStart, self.getY(line)) + self.paintGraph(0, xStart, self.getY(line) + 4, + width - xOffset*2 - xStart - 2, + thin=1) + pass + elif 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 == 'used': + totalStr = bytesToStr(total).rjust(5) + self.addString(totalStr, 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 = wmdocklib.getEvent() + while event is not None: + if event['type'] == 'destroynotify': + sys.exit(0) + elif event['type'] == 'buttonrelease': + area = wmdocklib.checkMouseRegion(event['x'],event['y']) + if area is not -1: + action = self._pathsToMonitor[area-1+self._skipping][3] + if action: + os.spawnvp(os.P_NOWAIT, action[0], action) + event = wmdocklib.getEvent() + + def updateMonitoredPaths(self): + index = 0 + pageoffset = self._skipping + for i in self._pathsToMonitor: + index += 1 + if index < pageoffset+1: + continue + if i is not None: + label, path, mode, action = i + self.paintLabel(index-pageoffset, label) + try: + hdData = self.getHdInfo(path) + except NotMounted: + hdData = (0, 0) + except OSError, e: + sys.stderr.write( + "Can't get hd data from %s: %s\n" % (path, str(e))) + hdData = (0, 0) + self.paintHdData(index-pageoffset, hdData, mode) + if index - pageoffset == 5: + break + + def mainLoop(self): + self.updateMonitoredPaths() + while 1: + self._checkEvents() + if self._actMonEnabled: + self.updateHdActivity() + wmdocklib.redraw() + time.sleep(0.1) + + +import signal +def handler(num, frame): + hdmon.updateMonitoredPaths() + signal.alarm(10) + +def parseCommandLine(argv): + '''Parse the commandline. Return a dictionary with options and values.''' + shorts = 'ht:f:g:b:r:c:p:s:' + longs = ['help', 'textcolor=', 'background=', 'barfgcolor=', + 'rgbfile=', 'configfile=', 'barbgcolor=', 'procstat=', + 'skipconf='] + 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 + if o in ('-s', '--skipconf'): + d['skipconf'] = 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 (, ) pairs. + colors = (('barfgcolor', 'graph'), + ('barbgcolor', 'graphbg'), + ('textcolor', 'text'), + ('background', 'background')) + for key, value in colors: + col = config.get(key) + if not col is None: + if col[0] is '#': code=col + else: code = wmdocklib.getColorCode(col, rgbFileName) + if code is None: + sys.stderr.write('Bad colorcode for %s, ignoring.\n' % key) + else: + wmdocklib.setColor(xpm, value, code) + +def 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 = wmdocklib.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,1000): + labelStr = str(i) + '.label' + pathStr = str(i) + '.path' + modeStr = str(i) + '.displaymode' + actionStr = str(i) + '.action' + label = config.get(labelStr) + if not label: break + path = config.get(pathStr) + action = config.get(actionStr) + if action: action=eval(action) + displayMode = config.get(modeStr, defaultMode) + if not displayMode in displayModes: + sys.stderr.write( + 'Unknown display mode: %s, using default.\n' % displayMode) + displayMode = defaultMode + pathsToMonitor.append((label[:3], path, displayMode, action)) + wmdocklib.addMouseRegion(i, + 8, 8 + (i - 1) * (letterHeight + 3), + 58, 4 + i * (letterHeight + 3)) + procStat = config.get('procstat', defaultProcStat) + skipping = int(config.get('skipconf', 0)) + actMonEnabled = int(config.get('monitoring')) + 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 + wmdocklib.setDefaultPixmap(xpm) + wmdocklib.openXwindow(sys.argv, width, height) + + signal.signal(signal.SIGCHLD, handler) + signal.signal(signal.SIGALRM, handler) + signal.alarm(10) + + global hdmon + hdmon = PywmHDMon(pathsToMonitor, procStat, actMonEnabled, skipping) + 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() diff --git a/examples/pywmseti.py b/examples/pywmseti.py new file mode 100755 index 0000000..e4a8e38 --- /dev/null +++ b/examples/pywmseti.py @@ -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 set the text color +-p, --progressbarcolor set the color of the progress bar +-g, --barbgcolor set the background color of the progress bar +-i, --indicatorcolor set the color of the running indicator +-b, --background set the background color +-d, --setidir set the directory where seti@home resides +-n, --nice set the nice value to run seti@home with +-r, --rgbfile set the rgb file to get color codes from +-c, --configfile set the config file to use +''' + +import sys +import time +import getopt +import os + +from pywmgeneral 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 (, ) 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() diff --git a/examples/pywmsysmon.py b/examples/pywmsysmon.py new file mode 100755 index 0000000..3cc4d47 --- /dev/null +++ b/examples/pywmsysmon.py @@ -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 set the foreground color of the memory bar +-g, --barbgcolor set the background color of the memory bar +-b, --background set the background color +-p, --graphforeground set the cpu graph foreground color +-a, --graphbackground set the cpu graph background color +-r, --rgbfile set the rgb file to get color codes from +-s, --procstat set the location of /proc/stat +-m, --procmeminfo set the location of /proc/meminfo +-i, --ignorenice ignore nice valued cpu usage +-u, --updatedelay delay (in seconds) between cpu graph updates +''' + +import sys +import time +import getopt +import os + +from pywmgeneral 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 (, ) 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() diff --git a/pywmdatetime/sample.pywmdatetimerc b/examples/sample.pywmdatetimerc similarity index 100% rename from pywmdatetime/sample.pywmdatetimerc rename to examples/sample.pywmdatetimerc diff --git a/examples/sample.pywmgenericrc b/examples/sample.pywmgenericrc new file mode 100644 index 0000000..8116077 --- /dev/null +++ b/examples/sample.pywmgenericrc @@ -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 - Call a method defined in the class UserMethods. See the +# source file for more information +# * exec - Execute an external command +# +# Available mouse actions are: +# * method - Same as above, see the source file for more information. +# * exec - 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 = - display a static string instead of the first line of +# the action-generated output. +# * update_delay = - 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 + diff --git a/examples/sample.pywmhdmonrc b/examples/sample.pywmhdmonrc new file mode 100644 index 0000000..35b39b7 --- /dev/null +++ b/examples/sample.pywmhdmonrc @@ -0,0 +1,50 @@ +[DEFAULT] + +# Displaymodes are used, free, percent or bar, displays the used size, +# free size, free percent and a bar representing space, respectively. + +1.label=/ +1.path=/ +#1.displaymode=free + +2.label=usr +2.path=/usr +#2.displaymode=free + +3.label=home +3.path=/home +#3.displaymode=free + +4.label=cd +4.path=/mnt/cd +4.displaymode=used +4.action=['/home/mario/bin/tmount', '/mnt/cd', 'eject'] + +5.label=jr +5.path=/mnt/jr +5.displaymode=used +5.action=['/home/mario/bin/tmount', '/mnt/jr', 'eject'] + +6.label=sm +6.path=/mnt/sm +6.displaymode=free +6.action=['/home/mario/bin/tmount', '/mnt/sm'] + +7.label=cf +7.path=/mnt/cf +7.displaymode=free +7.action=['/home/mario/bin/tmount', '/mnt/cf'] + +8.label=flo +8.path=/mnt/flo +8.displaymode=free +8.action=['/home/mario/bin/tmount', '/mnt/flo'] + +textcolor=light sea green +background=black +barfgcolor=light sea green +barbgcolor=grey45 +monitoring=0 + +#rgbfile=/usr/lib/X11/rgb.txt + diff --git a/examples/sample.pywmsetirc b/examples/sample.pywmsetirc new file mode 100644 index 0000000..da86ee4 --- /dev/null +++ b/examples/sample.pywmsetirc @@ -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 + diff --git a/examples/tmount b/examples/tmount new file mode 100644 index 0000000..943ffac --- /dev/null +++ b/examples/tmount @@ -0,0 +1,35 @@ +#!/bin/sh + +# tmount - toggle mount / eject +# +# usage: tmount mountpoint ejectable +# +# parameter mountpoint: the mount point, without trailing '/' +# ejectable: not empty indicates that the media is software ejectable +# action: if the indicated file system is not mounted, mounts it +# otherwise unmounts it +# if mounting fails or when unmounting, ejects software ejectable +# media. + +if [ "$2" == "" ]; then eject=echo +else eject=eject +fi + +mountpointIndicated=$1 +mountpointFound=`df $1 | tail -1 | cut -d% -f2` + +if [ $mountpointIndicated = $mountpointFound ] + then + + umount $mountpointIndicated + $eject $mountpointIndicated + +else + + # my smartmedia does not mount correctly after a media change + # second try always succeeds. ask me why! if neither mount + # attempt succeeds, then attempt ejecting ejectable media + + mount $mountpointIndicated || mount $mountpointIndicated || $eject $mountpointIndicated + +fi diff --git a/pywmdatetime/INSTALL b/pywmdatetime/INSTALL deleted file mode 100644 index 1dee547..0000000 --- a/pywmdatetime/INSTALL +++ /dev/null @@ -1,8 +0,0 @@ -1. If you don't have pywmgeneral installed, install it first. Can be found - at http://pywmdockapps.sourceforge.net - -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. - diff --git a/pywmdatetime/README b/pywmdatetime/README deleted file mode 100644 index 23719c8..0000000 --- a/pywmdatetime/README +++ /dev/null @@ -1,14 +0,0 @@ -[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, Mario Frasca - diff --git a/pywmdatetime/__init__.py b/pywmdatetime/__init__.py deleted file mode 100644 index bcdd476..0000000 --- a/pywmdatetime/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from pywmdatetime import * diff --git a/pywmgeneral/INSTALL b/pywmgeneral/INSTALL deleted file mode 100644 index 0407361..0000000 --- a/pywmgeneral/INSTALL +++ /dev/null @@ -1,10 +0,0 @@ -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. - diff --git a/pywmgeneral/PKG-INFO b/pywmgeneral/PKG-INFO deleted file mode 100644 index cccdaa0..0000000 --- a/pywmgeneral/PKG-INFO +++ /dev/null @@ -1,10 +0,0 @@ -Metadata-Version: 1.0 -Name: pywmgeneral -Version: 0.1 -Summary: Python module for making WindowMaker dockapps. -Home-page: http://pywmdockapps.sourceforge.net -Author: Mario Frasca -Author-email: mfrasca@interia.pl -License: GPL -Description: (previous author/email: Kristoffer Erlandsson ) -Platform: UNKNOWN diff --git a/pywmgeneral/README b/pywmgeneral/README deleted file mode 100644 index 34bca3f..0000000 --- a/pywmgeneral/README +++ /dev/null @@ -1,23 +0,0 @@ -[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, Mario -Frasca . - diff --git a/pywmgeneral/__init__.py b/pywmgeneral/__init__.py deleted file mode 100644 index 48f6c63..0000000 --- a/pywmgeneral/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from pywmhelpers import * diff --git a/pywmgeneral/pywmgeneral.c b/pywmgeneral/pywmgeneral.c deleted file mode 100644 index 58e2e2b..0000000 --- a/pywmgeneral/pywmgeneral.c +++ /dev/null @@ -1,596 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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= 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>= 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); - } -} diff --git a/pywmgeneral/pywmgeneral.h b/pywmgeneral/pywmgeneral.h deleted file mode 100644 index f532437..0000000 --- a/pywmgeneral/pywmgeneral.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 diff --git a/pywmgeneral/pywmhelpers.py b/pywmgeneral/pywmhelpers.py deleted file mode 100644 index bda6ad3..0000000 --- a/pywmgeneral/pywmhelpers.py +++ /dev/null @@ -1,253 +0,0 @@ -"""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.).*?c (?P#.*?) s (?P.*)") - 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 - - diff --git a/pywmgeneral/setup.py b/pywmgeneral/setup.py deleted file mode 100755 index f25ba1a..0000000 --- a/pywmgeneral/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -#! /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 = 'Mario Frasca', - author_email = 'mfrasca@interia.pl', - description = 'Python module for making WindowMaker dockapps.', - url = 'http://pywmdockapps.sourceforge.net', - license = 'GPL', - ext_modules = [module1]) - diff --git a/pywmgeneric/ChangeLog b/pywmgeneric/ChangeLog deleted file mode 100644 index 0f2dc05..0000000 --- a/pywmgeneric/ChangeLog +++ /dev/null @@ -1,8 +0,0 @@ -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. - - diff --git a/pywmgeneric/INSTALL b/pywmgeneric/INSTALL deleted file mode 100644 index b2fca26..0000000 --- a/pywmgeneric/INSTALL +++ /dev/null @@ -1,13 +0,0 @@ -1. If you don't have pywmgeneral installed, install it first. Can be found - at http://pywmdockapps.sourceforge.net. - -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 Mario Frasca . - diff --git a/pywmgeneric/README b/pywmgeneric/README deleted file mode 100644 index 026f2d0..0000000 --- a/pywmgeneric/README +++ /dev/null @@ -1,69 +0,0 @@ -[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 = - 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, Mario Frasca -. - -The newest version can be found at http://pywmdockapps.sourceforge.net/. -