199 lines
5.1 KiB
Python
Executable File
199 lines
5.1 KiB
Python
Executable File
#! /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()
|