diff --git a/pywmgeneric/pywmhelpers.py b/pywmgeneric/pywmhelpers.py new file mode 100644 index 0000000..bda6ad3 --- /dev/null +++ b/pywmgeneric/pywmhelpers.py @@ -0,0 +1,253 @@ +"""pywmhelpers.py + +Various helper functions when writing wm dockapps in Python. This module +is way better commented than the pywmgeneral one. This is the one +intented for use in applications. Many functions are just wrappers +around the ones in pywmgeneral but with nicer interfaces and better +documentation. + +Copyright (C) 2003 Kristoffer Erlandsson + +Licensed under the GNU General Public License + + +Changes: +2003-06-25 Kristoffer Erlandsson +Updated documentation + +2003-06-24 Kristoffer Erlandsson +Some changes to handle the additional event handling in pywmgeneral + +2003-06-16 Kristoffer Erlandsson +First workingish version +""" + +import os +import re +import ConfigParser + +import pywmgeneral + +def readConfigFile(fileName, errOut): + """Read the config file fileName. + + Return a dictionary with the options and values in the DEFAULT + section. Ignore everything else. The configuration file should not + get so complicated so that sections are needed. errOut is the + file-like object to which error messages will be printed. + """ + if not os.access(fileName, os.R_OK): + if errOut: + errOut.write( + 'Configuration file is not readable. Using defaults.\n') + return {} + cp = ConfigParser.ConfigParser() + try: + cp.read(fileName) + except ConfigParser.Error, e: + if errOut: + errOut.write('Error in configuration file:\n') + errOut.write(str(e) + '\nUsing defaults.') + return {} + defaults = cp.defaults() + if defaults == {}: + if errOut: + errOut.write( + 'Missing or empty DEFAULT section in the config file.\n') + errOut.write('Using defaults.\n') + return defaults + +def getCenterStartPos(s, letterWidth, areaWidth, offset): + """Get the x starting position if we want to paint s centred.""" + w = len(s) * letterWidth + textArea = areaWidth - offset * 2 - 1 + return (textArea - w) / 2 + +def addChar(ch, x, y, letterWidth, letterHeight, lettersStartX, lettersStartY, + letters, digitWidth, digitHeight, digitsStartX, digitsStartY, + digits, xOffset, yOffset, width, height): + """Paint the character ch at position x, y in the window. + + Return the (width, height) of the character painted. Raise + ValueError if we try to paint a char not in letters or digits + or if we get out of bounds during painting. digits is really + just another line of chars, it's unlucky called digits everywhere + I used it since it contained only digits in the start. However, + now it contains various special chars too everywhere I use it. But + the name remains in too many places so I haven't gotten to change + it. + """ + chIndex = letters.find(ch.lower()) + if chIndex != -1: + chX = lettersStartX + chIndex * letterWidth + chY = lettersStartY + w = letterWidth + h = letterHeight + else: + chIndex = digits.find(ch) + if chIndex != -1: + chX = digitsStartX + chIndex * digitWidth + chY = digitsStartY + w = digitWidth + h = digitHeight + else: + raise ValueError, "Unsupported char: '%s'" % ch + targX = x + xOffset + targY = y + yOffset + if targX + w > width - xOffset or targY + h > height - yOffset\ + or targX < 0 or targY < 0: + raise ValueError, "Out of bounds." + pywmgeneral.copyXPMArea(chX, chY, w, h, targX, targY) + return (w, h) + +def addString(s, x, y, letterWidth, letterHeight, lettersStartX, lettersStartY, + letters, digitWidth, digitHeight, digitsStartX, digitsStartY, + digits, xOffset, yOffset, width, height): + """Add a string at the given x and y positions. + + Call addChar repeatedely, so the same exception rules apply.""" + lastW = 0 + for letter in s: + w, h = addChar(letter, x + lastW, y, letterWidth, letterHeight, + lettersStartX, lettersStartY, letters, digitWidth, + digitHeight, digitsStartX, digitsStartY, digits, + xOffset, yOffset, width, height) + lastW += w + +def getVertSpacing(numLines, margin, height, letterHeight, yOffset): + """Return the optimal spacing between a number of lines. + + margin is the space we want between the first line and the top.""" + h = height - numLines * letterHeight - yOffset * 2 - margin + return h / (numLines - 1) + + +def readXPM(fileName): + """Read the xpm in filename. + + Return a list of strings containing the xpm. Raise IOError if we run + into trouble when trying to read the file. This function surely + doesn't handle all XPMs, but it handles the ones I use, so that'll + do. + """ + f = file(fileName, 'r') + lines = [l.rstrip('\n') for l in f.readlines()] + s = ''.join(lines) + res = [] + while 1: + nextStrStart = s.find('"') + if nextStrStart != -1: + nextStrEnd = s.find('"', nextStrStart + 1) + if nextStrEnd != -1: + res.append(s[nextStrStart+1:nextStrEnd]) + s = s[nextStrEnd+1:] + continue + break + return res + +def setColor(xpm, name, newColor): + """Find the color with comment name and set this color to newColor. + + Change the source code of an XPM represented as a list of strings. + I'm certain that this will fail on many XPMs too, but it'll do for + the ones I use. No check is done that the color is valid, this has + to be done elsewhere. + """ + colorRE = re.compile( + r"^(?P.).*?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/pywmgeneric/sample.pywmgenericrc b/pywmgeneric/sample.pywmgenericrc deleted file mode 100644 index 8116077..0000000 --- a/pywmgeneric/sample.pywmgenericrc +++ /dev/null @@ -1,69 +0,0 @@ -# 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 -