| #! /usr/bin/env 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() |