blob: 519b42806131729a13923f5801d2907fa0beea29 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossum9cf8f331992-03-30 10:54:51 +00002
3# Watch line printer queues (only works with BSD 4.3 lpq).
4#
5# This brings up a window containing one line per printer argument.
6#
7# Each line gives a small summary of the printer's status and queue.
8# The status tries to give as much relevant information as possible,
9# and gives extra info if you have jobs in the queue.
10#
11# The line's background color gives a hint at the status: navajo white
12# for idle, green if your job is now printing, yellow/orange for
13# small/large queue, red for errors.
14#
15# To reduce the duration of the unresponsive time while it is waiting
16# for an lpq subprocess to finish, it polls one printer every
17# delay/len(printers) seconds. A tiny dot indicates the last printer
18# updated. Hit the mouse button in the window to update the next one.
19#
20# To do:
21# - add an argument to override the default delay
22# - add arguments to override the default colors
23# - better heuristic for small/large queue (and more colors!)
24# - mouse clicks should update the printer clicked in
25# - better visual appearance, e.g., boxes around the lines?
26
27import posix
28import sys
29import time
30import string
31
32import stdwin
33from stdwinevents import *
34import mainloop
35
36# Default parameters
37DEF_PRINTER = 'oce' # This is CWI specific!
38DEF_DELAY = 10
39
40# Color assignments
41c_unknown = stdwin.fetchcolor('white')
42c_idle = stdwin.fetchcolor('navajo white')
43c_ontop = stdwin.fetchcolor('green')
44c_smallqueue = stdwin.fetchcolor('yellow')
45c_bigqueue = stdwin.fetchcolor('orange')
46c_error = stdwin.fetchcolor('red')
47
48def main():
49 delay = DEF_DELAY
50 #
51 try:
52 thisuser = posix.environ['LOGNAME']
53 except:
54 thisuser = posix.environ['USER']
55 #
56 printers = sys.argv[1:]
57 if printers:
58 # Strip '-P' from printer names just in case
59 # the user specified it...
60 for i in range(len(printers)):
61 if printers[i][:2] == '-P':
62 printers[i] = printers[i][2:]
63 else:
64 if posix.environ.has_key('PRINTER'):
65 printers = [posix.environ['PRINTER']]
66 else:
67 printers = [DEF_PRINTER]
68 #
69 width = stdwin.textwidth('in')*20
70 height = len(printers) * stdwin.lineheight() + 5
71 stdwin.setdefwinsize(width, height)
72 stdwin.setdefscrollbars(0, 0)
73 #
74 win = stdwin.open('lpwin')
75 #
76 win.printers = printers
77 win.colors = [c_unknown] * len(printers)
78 win.texts = printers[:]
79 win.next = 0
80 win.delay = DEF_DELAY
81 win.thisuser = thisuser
82 win.dispatch = lpdispatch
83 #
84 win.settimer(1)
85 #
86 mainloop.register(win)
87 mainloop.mainloop()
88
Guido van Rossumd55f4d11993-12-17 14:39:12 +000089def lpdispatch(event):
90 type, win, detail = event
Guido van Rossum9cf8f331992-03-30 10:54:51 +000091 if type == WE_CLOSE or type == WE_CHAR and detail in ('q', 'Q'):
92 mainloop.unregister(win)
93 elif type == WE_DRAW:
94 drawproc(win)
95 elif type == WE_TIMER:
96 update(win)
97 win.change((0,0), (10000, 10000))
98 elif type == WE_MOUSE_UP:
99 win.settimer(1)
100
101def drawproc(win):
102 d = win.begindrawing()
103 offset = d.textwidth('.')
104 h, v = 0, 0
105 for i in range(len(win.printers)):
106 text = win.texts[i]
107 color = win.colors[i]
108 d.setbgcolor(color)
109 d.erase((h, v), (h+10000, v+d.lineheight()))
110 if (i+1) % len(win.printers) == win.next and color <> c_unknown:
111 d.text((h, v), '.')
112 d.text((h+offset, v), text)
113 v = v + d.lineheight()
114
115def update(win):
116 i = win.next
117 win.next = (i+1) % len(win.printers)
118 win.texts[i], win.colors[i] = makestatus(win.printers[i], win.thisuser)
119 win.settimer(int(win.delay * 10.0 / len(win.printers)))
120
121def makestatus(name, thisuser):
122 pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r')
123 lines = []
124 users = {}
125 aheadbytes = 0
126 aheadjobs = 0
127 userseen = 0
128 totalbytes = 0
129 totaljobs = 0
130 color = c_unknown
131 while 1:
132 line = pipe.readline()
133 if not line: break
134 fields = string.split(line)
135 n = len(fields)
136 if len(fields) >= 6 and fields[n-1] == 'bytes':
137 rank = fields[0]
138 user = fields[1]
139 job = fields[2]
140 files = fields[3:-2]
141 bytes = eval(fields[n-2])
142 if user == thisuser:
143 userseen = 1
144 if aheadjobs == 0:
145 color = c_ontop
146 elif not userseen:
147 aheadbytes = aheadbytes + bytes
148 aheadjobs = aheadjobs + 1
149 totalbytes = totalbytes + bytes
150 totaljobs = totaljobs + 1
151 if color == c_unknown:
152 color = c_smallqueue
153 elif color == c_smallqueue:
154 color = c_bigqueue
155 if users.has_key(user):
156 ujobs, ubytes = users[user]
157 else:
158 ujobs, ubytes = 0, 0
159 ujobs = ujobs + 1
160 ubytes = ubytes + bytes
161 users[user] = ujobs, ubytes
162 else:
163 if fields and fields[0] <> 'Rank':
164 line = string.strip(line)
165 if line == 'no entries':
166 line = name + ': idle'
167 if color == c_unknown:
168 color = c_idle
169 elif line[-22:] == ' is ready and printing':
170 line = line[:-22]
171 else:
172 line = name + ': ' + line
173 color = c_error
174 lines.append(line)
175 #
176 if totaljobs:
177 line = `(totalbytes+1023)/1024` + ' K'
178 if totaljobs <> len(users):
179 line = line + ' (' + `totaljobs` + ' jobs)'
180 if len(users) == 1:
181 line = line + ' for ' + users.keys()[0]
182 else:
183 line = line + ' for ' + `len(users)` + ' users'
184 if userseen:
185 if aheadjobs == 0:
186 line = line + ' (' + thisuser + ' first)'
187 else:
188 line = line + ' (' + `(aheadbytes+1023)/1024`
189 line = line + ' K before ' + thisuser + ')'
190 lines.append(line)
191 #
192 sts = pipe.close()
193 if sts:
194 lines.append('lpq exit status ' + `sts`)
195 color = c_error
196 return string.joinfields(lines, ': '), color
197
198main()