1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
# 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 = []
# Last window that ever received an event
#
last_window = None
# 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.
win.dispatch((WE_NULL, win, None))
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):
global last_window
if win == last_window:
last_window = None
if win in windows:
windows.remove(win) # Not in 0.9.1
# 0.9.1 solution:
#for i in range(len(windows)):
# if windows[i] = win:
# del windows[i]
# break
# Interfaces used by WindowSched.
#
def countwindows():
return len(windows)
#
def anywindow():
if windows:
return windows[0]
else:
return None
# 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])
# 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.
#
recursion_level = 0 # Hack to make it reentrant
def mainloop():
global recursion_level
recursion_level = recursion_level + 1
try:
stdwin_select_handler() # Process events already in queue
while 1:
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()
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:
do_select()
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
# 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:
try:
event = stdwinq.getevent()
except KeyboardInterrupt:
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)
# Dispatch a single event.
# 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).
# Windows not in the windows list don't get their events:
# events for such windows are silently ignored.
#
def dispatch(event):
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:
#
def __init__(self, title):
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)
|