1 # Standard main loop for *all* STDWIN applications.
2 # This requires that applications:
3 # - register their windows on creation and unregister them when closed
4 # - have a 'dispatch' function as a window member
8 from stdwinevents
import *
11 # List of windows known to the main loop.
16 # Last window that ever received an event
21 # Function to register a window.
24 # First test the dispatch function by passing it a null event --
25 # this catches registration of unconforming windows.
26 win
.dispatch((WE_NULL
, win
, None))
27 if win
not in windows
:
31 # Function to unregister a window.
32 # It is not an error to unregister an already unregistered window
33 # (this is useful for cleanup actions).
37 if win
== last_window
:
40 windows
.remove(win
) # Not in 0.9.1
42 #for i in range(len(windows)):
43 # if windows[i] = win:
48 # Interfaces used by WindowSched.
60 # NEW: register any number of file descriptors
64 select_handlers
= None
66 def registerfd(fd
, mode
, handler
):
67 if mode
not in ('r', 'w', 'x'):
68 raise ValueError, 'mode must be r, w or x'
69 if type(fd
) <> type(0):
70 fd
= fd
.fileno() # If this fails it's not a proper select arg
71 for i
in range(len(fdlist
)):
72 if fdlist
[i
][:2] == (fd
, mode
):
74 '(fd, mode) combination already registered'
75 fdlist
.append((fd
, mode
, handler
))
78 def unregisterfd(fd
, *args
):
79 if type(fd
) <> type(0):
80 fd
= fd
.fileno() # If this fails it's not a proper select arg
83 for i
in range(len(fdlist
)):
84 if fdlist
[i
][:n
] == args
:
88 def make_select_args():
89 global select_args
, select_handlers
90 rlist
, wlist
, xlist
= [], [], []
91 rhandlers
, whandlers
, xhandlers
= {}, {}, {}
92 for fd
, mode
, handler
in fdlist
:
95 rhandlers
[`fd`
] = handler
98 whandlers
[`fd`
] = handler
101 xhandlers
[`fd`
] = handler
102 if rlist
or wlist
or xlist
:
103 select_args
= rlist
, wlist
, xlist
104 select_handlers
= rhandlers
, whandlers
, xhandlers
107 select_handlers
= None
111 reply
= apply(select
.select
, select_args
)
115 handler
= select_handlers
[mode
][`fd`
]
116 handler(fd
, 'rwx'[mode
])
119 # Event processing main loop.
120 # Return when there are no windows left, or when an unhandled
121 # exception occurs. (It is safe to restart the main loop after
122 # an unsuccessful exit.)
123 # Python's stdwin.getevent() turns WE_COMMAND/WC_CANCEL events
124 # into KeyboardInterrupt exceptions; these are turned back in events.
126 recursion_level
= 0 # Hack to make it reentrant
128 global recursion_level
129 recursion_level
= recursion_level
+ 1
131 stdwin_select_handler() # Process events already in queue
133 if windows
and not fdlist
:
134 while windows
and not fdlist
:
136 event
= stdwinq
.getevent()
137 except KeyboardInterrupt:
138 event
= (WE_COMMAND
, \
141 elif windows
and fdlist
:
143 if recursion_level
== 1:
144 registerfd(fd
, 'r', stdwin_select_handler
)
148 stdwin_select_handler()
150 if recursion_level
== 1:
153 while fdlist
and not windows
:
158 recursion_level
= recursion_level
- 1
161 # Check for events without ever blocking
164 stdwin_select_handler()
165 # XXX Should check for socket stuff as well
168 # Handle stdwin events until none are left
170 def stdwin_select_handler(*args
):
173 event
= stdwinq
.pollevent()
174 except KeyboardInterrupt:
175 event
= (WE_COMMAND
, None, WC_CANCEL
)
181 # Run a modal dialog loop for a window. The dialog window must have
182 # been registered first. This prohibits most events (except size/draw
183 # events) to other windows. The modal dialog loop ends when the
184 # dialog window unregisters itself.
186 passthrough
= WE_SIZE
, WE_DRAW
187 beeping
= WE_MOUSE_DOWN
, WE_COMMAND
, WE_CHAR
, WE_KEY
, WE_CLOSE
, WE_MENU
189 def modaldialog(window
):
190 if window
not in windows
:
191 raise ValueError, 'modaldialog window not registered'
192 while window
in windows
:
194 event
= stdwinq
.getevent()
195 except KeyboardInterrupt:
196 event
= WE_COMMAND
, None, WC_CANCEL
197 etype
, ewindow
, edetail
= event
198 if etype
not in passthrough
and ewindow
<> window
:
205 # Dispatch a single event.
206 # Events for the no window in particular are sent to the active window
207 # or to the last window that received an event (these hacks are for the
208 # WE_LOST_SEL event, which is directed to no particular window).
209 # Windows not in the windows list don't get their events:
210 # events for such windows are silently ignored.
215 active
= stdwin
.getactive()
216 if active
: last_window
= active
218 last_window
= event
[1]
219 if last_window
in windows
:
220 last_window
.dispatch(event
)
227 def __init__(self
, title
):
228 self
.window
= stdwin
.open(title
)
229 self
.window
.dispatch
= self
.dispatch
230 register(self
.window
)
233 unregister(self
.window
)
234 del self
.window
.dispatch
237 def dispatch(self
, event
):
238 etype
, ewindow
, edetail
= event
239 if etype
== WE_CLOSE
:
243 # Standard modal dialogs
244 # XXX implemented using stdwin dialogs for now
246 def askstr(prompt
, default
):
247 return stdwin
.askstr(prompt
, default
)
249 def askync(prompt
, yesorno
):
250 return stdwin
.askync(prompt
, yesorno
)
252 def askfile(prompt
, default
, new
):
253 return stdwin
.askfile(prompt
, default
, new
)