| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | # Standard main loop for *all* STDWIN applications. | 
					
						
							|  |  |  | # This requires that applications: | 
					
						
							|  |  |  | # - register their windows on creation and unregister them when closed | 
					
						
							|  |  |  | # - have a 'dispatch' function as a window member | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import stdwin, stdwinq | 
					
						
							|  |  |  | from stdwinevents import * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # List of windows known to the main loop. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | windows = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | # Last window that ever received an event | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | last_window = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | # Function to register a window. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def register(win): | 
					
						
							|  |  |  | 	# First test the dispatch function by passing it a null event -- | 
					
						
							|  |  |  | 	# this catches registration of unconforming windows. | 
					
						
							| 
									
										
										
										
											1992-12-14 12:57:56 +00:00
										 |  |  | 	win.dispatch((WE_NULL, win, None)) | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | 	if win not in windows: | 
					
						
							|  |  |  | 		windows.append(win) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Function to unregister a window. | 
					
						
							|  |  |  | # It is not an error to unregister an already unregistered window | 
					
						
							|  |  |  | # (this is useful for cleanup actions). | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def unregister(win): | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 	global last_window | 
					
						
							|  |  |  | 	if win == last_window: | 
					
						
							|  |  |  | 		last_window = None | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | 	if win in windows: | 
					
						
							|  |  |  | 		windows.remove(win) # Not in 0.9.1 | 
					
						
							| 
									
										
										
										
											1991-11-19 20:41:07 +00:00
										 |  |  | 		# 0.9.1 solution: | 
					
						
							|  |  |  | 		#for i in range(len(windows)): | 
					
						
							|  |  |  | 		#	if windows[i] = win: | 
					
						
							|  |  |  | 		#		del windows[i] | 
					
						
							|  |  |  | 		#		break | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Interfaces used by WindowSched. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def countwindows(): | 
					
						
							|  |  |  | 	return len(windows) | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def anywindow(): | 
					
						
							|  |  |  | 	if windows: | 
					
						
							|  |  |  | 		return windows[0] | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | # NEW: register any number of file descriptors | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | fdlist = [] | 
					
						
							|  |  |  | select_args = None | 
					
						
							|  |  |  | select_handlers = None | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def registerfd(fd, mode, handler): | 
					
						
							|  |  |  | 	if mode not in ('r', 'w', 'x'): | 
					
						
							|  |  |  | 		raise ValueError, 'mode must be r, w or x' | 
					
						
							|  |  |  | 	if type(fd) <> type(0): | 
					
						
							|  |  |  | 		fd = fd.fileno() # If this fails it's not a proper select arg | 
					
						
							|  |  |  | 	for i in range(len(fdlist)): | 
					
						
							|  |  |  | 		if fdlist[i][:2] == (fd, mode): | 
					
						
							|  |  |  | 			raise ValueError, \ | 
					
						
							|  |  |  | 				'(fd, mode) combination already registered' | 
					
						
							|  |  |  | 	fdlist.append((fd, mode, handler)) | 
					
						
							|  |  |  | 	make_select_args() | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def unregisterfd(fd, *args): | 
					
						
							|  |  |  | 	if type(fd) <> type(0): | 
					
						
							|  |  |  | 		fd = fd.fileno() # If this fails it's not a proper select arg | 
					
						
							|  |  |  | 	args = (fd,) + args | 
					
						
							|  |  |  | 	n = len(args) | 
					
						
							|  |  |  | 	for i in range(len(fdlist)): | 
					
						
							|  |  |  | 		if fdlist[i][:n] == args: | 
					
						
							|  |  |  | 			del fdlist[i] | 
					
						
							|  |  |  | 	make_select_args() | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def make_select_args(): | 
					
						
							|  |  |  | 	global select_args, select_handlers | 
					
						
							|  |  |  | 	rlist, wlist, xlist = [], [], [] | 
					
						
							|  |  |  | 	rhandlers, whandlers, xhandlers = {}, {}, {} | 
					
						
							|  |  |  | 	for fd, mode, handler in fdlist: | 
					
						
							|  |  |  | 		if mode == 'r': | 
					
						
							|  |  |  | 			rlist.append(fd) | 
					
						
							|  |  |  | 			rhandlers[`fd`] = handler | 
					
						
							|  |  |  | 		if mode == 'w': | 
					
						
							|  |  |  | 			wlist.append(fd) | 
					
						
							|  |  |  | 			whandlers[`fd`] = handler | 
					
						
							|  |  |  | 		if mode == 'x': | 
					
						
							|  |  |  | 			xlist.append(fd) | 
					
						
							|  |  |  | 			xhandlers[`fd`] = handler | 
					
						
							|  |  |  | 	if rlist or wlist or xlist: | 
					
						
							|  |  |  | 		select_args = rlist, wlist, xlist | 
					
						
							|  |  |  | 		select_handlers = rhandlers, whandlers, xhandlers | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		select_args = None | 
					
						
							|  |  |  | 		select_handlers = None | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def do_select(): | 
					
						
							|  |  |  | 	import select | 
					
						
							|  |  |  | 	reply = apply(select.select, select_args) | 
					
						
							|  |  |  | 	for mode in 0, 1, 2: | 
					
						
							|  |  |  | 		list = reply[mode] | 
					
						
							|  |  |  | 		for fd in list: | 
					
						
							|  |  |  | 			handler = select_handlers[mode][`fd`] | 
					
						
							|  |  |  | 			handler(fd, 'rwx'[mode]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | # Event processing main loop. | 
					
						
							|  |  |  | # Return when there are no windows left, or when an unhandled | 
					
						
							|  |  |  | # exception occurs.  (It is safe to restart the main loop after | 
					
						
							|  |  |  | # an unsuccessful exit.) | 
					
						
							|  |  |  | # Python's stdwin.getevent() turns WE_COMMAND/WC_CANCEL events | 
					
						
							|  |  |  | # into KeyboardInterrupt exceptions; these are turned back in events. | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											1993-01-04 09:16:51 +00:00
										 |  |  | recursion_level = 0 # Hack to make it reentrant | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | def mainloop(): | 
					
						
							| 
									
										
										
										
											1993-01-04 09:16:51 +00:00
										 |  |  | 	global recursion_level | 
					
						
							|  |  |  | 	recursion_level = recursion_level + 1 | 
					
						
							|  |  |  | 	try: | 
					
						
							|  |  |  | 		stdwin_select_handler() # Process events already in queue | 
					
						
							|  |  |  | 		while 1: | 
					
						
							| 
									
										
										
										
											1993-01-21 15:36:40 +00:00
										 |  |  | 			if windows and not fdlist: | 
					
						
							|  |  |  | 				while windows and not fdlist: | 
					
						
							|  |  |  | 					try: | 
					
						
							|  |  |  | 						event = stdwinq.getevent() | 
					
						
							|  |  |  | 					except KeyboardInterrupt: | 
					
						
							|  |  |  | 						event = (WE_COMMAND, \ | 
					
						
							|  |  |  | 							 None, WC_CANCEL) | 
					
						
							|  |  |  | 					dispatch(event) | 
					
						
							|  |  |  | 			elif windows and fdlist: | 
					
						
							|  |  |  | 				fd = stdwin.fileno() | 
					
						
							| 
									
										
										
										
											1993-01-04 09:16:51 +00:00
										 |  |  | 				if recursion_level == 1: | 
					
						
							|  |  |  | 				    registerfd(fd, 'r', stdwin_select_handler) | 
					
						
							|  |  |  | 				try: | 
					
						
							|  |  |  | 					while windows: | 
					
						
							|  |  |  | 						do_select() | 
					
						
							|  |  |  | 						stdwin_select_handler() | 
					
						
							|  |  |  | 				finally: | 
					
						
							|  |  |  | 					if recursion_level == 1: | 
					
						
							|  |  |  | 						unregisterfd(fd) | 
					
						
							|  |  |  | 			elif fdlist: | 
					
						
							|  |  |  | 				while fdlist and not windows: | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 					do_select() | 
					
						
							| 
									
										
										
										
											1993-01-04 09:16:51 +00:00
										 |  |  | 			else: | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 	finally: | 
					
						
							|  |  |  | 		recursion_level = recursion_level - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Check for events without ever blocking | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def check(): | 
					
						
							|  |  |  | 	stdwin_select_handler() | 
					
						
							|  |  |  | 	# XXX Should check for socket stuff as well | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Handle stdwin events until none are left | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def stdwin_select_handler(*args): | 
					
						
							|  |  |  | 	while 1: | 
					
						
							|  |  |  | 		try: | 
					
						
							|  |  |  | 			event = stdwinq.pollevent() | 
					
						
							|  |  |  | 		except KeyboardInterrupt: | 
					
						
							|  |  |  | 			event = (WE_COMMAND, None, WC_CANCEL) | 
					
						
							|  |  |  | 		if event is None: | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		dispatch(event) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Run a modal dialog loop for a window.  The dialog window must have | 
					
						
							|  |  |  | # been registered first.  This prohibits most events (except size/draw | 
					
						
							|  |  |  | # events) to other windows.  The modal dialog loop ends when the | 
					
						
							|  |  |  | # dialog window unregisters itself. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | passthrough = WE_SIZE, WE_DRAW | 
					
						
							|  |  |  | beeping = WE_MOUSE_DOWN, WE_COMMAND, WE_CHAR, WE_KEY, WE_CLOSE, WE_MENU | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def modaldialog(window): | 
					
						
							|  |  |  | 	if window not in windows: | 
					
						
							|  |  |  | 		raise ValueError, 'modaldialog window not registered' | 
					
						
							|  |  |  | 	while window in windows: | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | 		try: | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 			event = stdwinq.getevent() | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | 		except KeyboardInterrupt: | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 			event = WE_COMMAND, None, WC_CANCEL | 
					
						
							|  |  |  | 		etype, ewindow, edetail = event | 
					
						
							|  |  |  | 		if etype not in passthrough and ewindow <> window: | 
					
						
							|  |  |  | 			if etype in beeping: | 
					
						
							|  |  |  | 				stdwin.fleep() | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		dispatch(event) | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Dispatch a single event. | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | # Events for the no window in particular are sent to the active window | 
					
						
							|  |  |  | # or to the last window that received an event (these hacks are for the | 
					
						
							|  |  |  | # WE_LOST_SEL event, which is directed to no particular window). | 
					
						
							| 
									
										
										
										
											1991-08-16 13:28:28 +00:00
										 |  |  | # Windows not in the windows list don't get their events: | 
					
						
							|  |  |  | # events for such windows are silently ignored. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def dispatch(event): | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 	global last_window | 
					
						
							|  |  |  | 	if event[1] == None: | 
					
						
							|  |  |  | 		active = stdwin.getactive() | 
					
						
							|  |  |  | 		if active: last_window = active | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		last_window = event[1] | 
					
						
							|  |  |  | 	if last_window in windows: | 
					
						
							|  |  |  | 		last_window.dispatch(event) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Dialog base class | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | class Dialog: | 
					
						
							|  |  |  | 	# | 
					
						
							| 
									
										
										
										
											1993-12-17 15:25:27 +00:00
										 |  |  | 	def __init__(self, title): | 
					
						
							| 
									
										
										
										
											1992-11-26 09:17:19 +00:00
										 |  |  | 		self.window = stdwin.open(title) | 
					
						
							|  |  |  | 		self.window.dispatch = self.dispatch | 
					
						
							|  |  |  | 		register(self.window) | 
					
						
							|  |  |  | 	# | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							|  |  |  | 		unregister(self.window) | 
					
						
							|  |  |  | 		del self.window.dispatch | 
					
						
							|  |  |  | 		self.window.close() | 
					
						
							|  |  |  | 	# | 
					
						
							|  |  |  | 	def dispatch(self, event): | 
					
						
							|  |  |  | 		etype, ewindow, edetail = event | 
					
						
							|  |  |  | 		if etype == WE_CLOSE: | 
					
						
							|  |  |  | 			self.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Standard modal dialogs | 
					
						
							|  |  |  | # XXX implemented using stdwin dialogs for now | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def askstr(prompt, default): | 
					
						
							|  |  |  | 	return stdwin.askstr(prompt, default) | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def askync(prompt, yesorno): | 
					
						
							|  |  |  | 	return stdwin.askync(prompt, yesorno) | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def askfile(prompt, default, new): | 
					
						
							|  |  |  | 	return stdwin.askfile(prompt, default, new) | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | def message(msg): | 
					
						
							|  |  |  | 	stdwin.message(msg) |