Rewritten somewhat again, distinguished between internal and external
methods (internal ones start with '_'), asynchronous transfers are now
killed synchronously (i.e. after t.kill(), t.busy() is false immediately).
diff --git a/Demo/tkinter/guido/ManPage.py b/Demo/tkinter/guido/ManPage.py
index b13f47f..b6ade64 100755
--- a/Demo/tkinter/guido/ManPage.py
+++ b/Demo/tkinter/guido/ManPage.py
@@ -18,6 +18,7 @@
 # Basic Man Page class -- does not disable editing
 class EditableManPage(ScrolledText):
 
+	# Initialize instance
 	def __init__(self, master=None, cnf={}):
 		# Initialize base class
 		ScrolledText.__init__(self, master, cnf)
@@ -27,37 +28,77 @@
 		self.tag_config('!', {'font': ITALICFONT})
 		self.tag_config('_', {'underline': 1})
 
-	def parsefile(self, fp):
-		if hasattr(self, 'buffer'):
-			raise RuntimeError, 'Still busy parsing!'
+		# Set state to idle
+		self.fp = None
+		self.lineno = 0
+
+	# Test whether we are busy parsing a file
+	def busy(self):
+		return self.fp != None
+
+	# Ensure we're not busy
+	def kill(self):
+		if self.busy():
+			self._endparser()
+
+	# Parse a file, in the background
+	def asyncparsefile(self, fp):
+		self._startparser(fp)
+		self.tk.createfilehandler(fp, tkinter.READABLE,
+					  self._filehandler)
+
+	parsefile = asyncparsefile	# Alias
+
+	# I/O handler used by background parsing
+	def _filehandler(self, fp, mask):
+		nextline = self.fp.readline()
+		if not nextline:
+			self._endparser()
+			return
+		self._parseline(nextline)
+
+	# Parse a file, now (cannot be aborted)
+	def syncparsefile(self, fp):
 		from select import select
 		def avail(fp=fp, tout=0.0, select=select):
 			return select([fp], [], [], tout)[0]
 		height = self.getint(self['height'])
-		self.startparser()
+		self._startparser(fp)
 		while 1:
-			if self.lineno < height or \
-			   self.lineno%10 == 0 or not avail():
-				self.update()
 			nextline = fp.readline()
 			if not nextline:
 				break
-			self.parseline(nextline)
-		self.endparser()
-		self.update()
+			self._parseline(nextline)
+		self._endparser()
 
-	def startparser(self):
+	# Initialize parsing from a particular file -- must not be busy
+	def _startparser(self, fp):
+		if self.busy():
+			raise RuntimeError, 'startparser: still busy'
+		fp.fileno()		# Test for file-ness
+		self.fp = fp
 		self.lineno = 0
 		self.ok = 0
 		self.empty = 0
 		self.buffer = None
+		self.delete('1.0', 'end')
 
-	def endparser(self):
+	# End parsing -- must be busy, need not be at EOF
+	def _endparser(self):
+		if not self.busy():
+			raise RuntimeError, 'endparser: not busy'
 		if self.buffer:
-			self.parseline('')
+			self._parseline('')
+		try:
+			self.tk.deletefilehandler(self.fp)
+		except TclError, msg:
+			pass
+		self.fp.close()
+		self.fp = None
 		del self.ok, self.empty, self.buffer
 
-	def parseline(self, nextline):
+	# Parse a single line
+	def _parseline(self, nextline):
 		if not self.buffer:
 			# Save this line -- we need one line read-ahead
 			self.buffer = nextline
@@ -90,12 +131,12 @@
 		if self.empty:
 			# One or more previous lines were empty
 			# -- insert one blank line in the text
-			self.insert_prop('\n')
+			self._insert_prop('\n')
 			self.lineno = self.lineno + 1
 			self.empty = 0
 		if not propline:
 			# No properties
-			self.insert_prop(textline)
+			self._insert_prop(textline)
 			self.lineno = self.lineno + 1
 			return
 		# Search for properties
@@ -104,25 +145,26 @@
 		for i in range(min(len(propline), len(textline))):
 			if propline[i] != p:
 				if j < i:
-					self.insert_prop(textline[j:i], p)
+					self._insert_prop(textline[j:i], p)
 					j = i
 				p = propline[i]
-		self.insert_prop(textline[j:])
+		self._insert_prop(textline[j:])
 		self.lineno = self.lineno + 1
 
-	def insert_prop(self, str, prop = ' '):
+	# Insert a string at the end, with at most one property (tag)
+	def _insert_prop(self, str, prop = ' '):
 		here = self.index('end')
-		self.insert('end', str[0])
+		self.insert('end', str)
 		tags = self.tag_names(here)
 		for tag in tags:
-			self.tag_remove(tag, here)
+			self.tag_remove(tag, here, 'end')
 		if prop != ' ':
-			self.tag_add(prop, here)
-		self.insert('end', str[1:])
+			self.tag_add(prop, here, 'end')
 
 # Readonly Man Page class -- disables editing, otherwise the same
 class ReadonlyManPage(EditableManPage):
 
+	# Initialize instance
 	def __init__(self, master=None, cnf={}):
 		# Initialize base class
 		EditableManPage.__init__(self, master, cnf)
@@ -136,6 +178,7 @@
 		self.bind('<Control-d>', self.modify_cb)
 		self.bind('<Control-v>', self.modify_cb)
 
+	# You could override this to ring the bell, etc.
 	def modify_cb(self, e):
 		pass