#! /usr/local/bin/python # Watch line printer queues (only works with BSD 4.3 lpq). # # This brings up a window containing one line per printer argument. # # Each line gives a small summary of the printer's status and queue. # The status tries to give as much relevant information as possible, # and gives extra info if you have jobs in the queue. # # The line's background color gives a hint at the status: navajo white # for idle, green if your job is now printing, yellow/orange for # small/large queue, red for errors. # # To reduce the duration of the unresponsive time while it is waiting # for an lpq subprocess to finish, it polls one printer every # delay/len(printers) seconds. A tiny dot indicates the last printer # updated. Hit the mouse button in the window to update the next one. # # To do: # - add an argument to override the default delay # - add arguments to override the default colors # - better heuristic for small/large queue (and more colors!) # - mouse clicks should update the printer clicked in # - better visual appearance, e.g., boxes around the lines? import posix import sys import time import string import stdwin from stdwinevents import * import mainloop # Default parameters DEF_PRINTER = 'oce' # This is CWI specific! DEF_DELAY = 10 # Color assignments c_unknown = stdwin.fetchcolor('white') c_idle = stdwin.fetchcolor('navajo white') c_ontop = stdwin.fetchcolor('green') c_smallqueue = stdwin.fetchcolor('yellow') c_bigqueue = stdwin.fetchcolor('orange') c_error = stdwin.fetchcolor('red') def main(): delay = DEF_DELAY # try: thisuser = posix.environ['LOGNAME'] except: thisuser = posix.environ['USER'] # printers = sys.argv[1:] if printers: # Strip '-P' from printer names just in case # the user specified it... for i in range(len(printers)): if printers[i][:2] == '-P': printers[i] = printers[i][2:] else: if posix.environ.has_key('PRINTER'): printers = [posix.environ['PRINTER']] else: printers = [DEF_PRINTER] # width = stdwin.textwidth('in')*20 height = len(printers) * stdwin.lineheight() + 5 stdwin.setdefwinsize(width, height) stdwin.setdefscrollbars(0, 0) # win = stdwin.open('lpwin') # win.printers = printers win.colors = [c_unknown] * len(printers) win.texts = printers[:] win.next = 0 win.delay = DEF_DELAY win.thisuser = thisuser win.dispatch = lpdispatch # win.settimer(1) # mainloop.register(win) mainloop.mainloop() def lpdispatch(event): type, win, detail = event if type == WE_CLOSE or type == WE_CHAR and detail in ('q', 'Q'): mainloop.unregister(win) elif type == WE_DRAW: drawproc(win) elif type == WE_TIMER: update(win) win.change((0,0), (10000, 10000)) elif type == WE_MOUSE_UP: win.settimer(1) def drawproc(win): d = win.begindrawing() offset = d.textwidth('.') h, v = 0, 0 for i in range(len(win.printers)): text = win.texts[i] color = win.colors[i] d.setbgcolor(color) d.erase((h, v), (h+10000, v+d.lineheight())) if (i+1) % len(win.printers) == win.next and color <> c_unknown: d.text((h, v), '.') d.text((h+offset, v), text) v = v + d.lineheight() def update(win): i = win.next win.next = (i+1) % len(win.printers) win.texts[i], win.colors[i] = makestatus(win.printers[i], win.thisuser) win.settimer(int(win.delay * 10.0 / len(win.printers))) def makestatus(name, thisuser): pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r') lines = [] users = {} aheadbytes = 0 aheadjobs = 0 userseen = 0 totalbytes = 0 totaljobs = 0 color = c_unknown while 1: line = pipe.readline() if not line: break fields = string.split(line) n = len(fields) if len(fields) >= 6 and fields[n-1] == 'bytes': rank = fields[0] user = fields[1] job = fields[2] files = fields[3:-2] bytes = eval(fields[n-2]) if user == thisuser: userseen = 1 if aheadjobs == 0: color = c_ontop elif not userseen: aheadbytes = aheadbytes + bytes aheadjobs = aheadjobs + 1 totalbytes = totalbytes + bytes totaljobs = totaljobs + 1 if color == c_unknown: color = c_smallqueue elif color == c_smallqueue: color = c_bigqueue if users.has_key(user): ujobs, ubytes = users[user] else: ujobs, ubytes = 0, 0 ujobs = ujobs + 1 ubytes = ubytes + bytes users[user] = ujobs, ubytes else: if fields and fields[0] <> 'Rank': line = string.strip(line) if line == 'no entries': line = name + ': idle' if color == c_unknown: color = c_idle elif line[-22:] == ' is ready and printing': line = line[:-22] else: line = name + ': ' + line color = c_error lines.append(line) # if totaljobs: line = `(totalbytes+1023)/1024` + ' K' if totaljobs <> len(users): line = line + ' (' + `totaljobs` + ' jobs)' if len(users) == 1: line = line + ' for ' + users.keys()[0] else: line = line + ' for ' + `len(users)` + ' users' if userseen: if aheadjobs == 0: line = line + ' (' + thisuser + ' first)' else: line = line + ' (' + `(aheadbytes+1023)/1024` line = line + ' K before ' + thisuser + ')' lines.append(line) # sts = pipe.close() if sts: lines.append('lpq exit status ' + `sts`) color = c_error return string.joinfields(lines, ': '), color main()