1313windows = []
1414
1515
16+ # Last window that ever received an event
17+ #
18+ last_window = None
19+
20+
1621# Function to register a window.
1722#
1823def register (win ):
@@ -28,6 +33,9 @@ def register(win):
2833# (this is useful for cleanup actions).
2934#
3035def unregister (win ):
36+ global last_window
37+ if win == last_window :
38+ last_window = None
3139 if win in windows :
3240 windows .remove (win ) # Not in 0.9.1
3341 # 0.9.1 solution:
@@ -49,6 +57,65 @@ def anywindow():
4957 return None
5058
5159
60+ # NEW: register any number of file descriptors
61+ #
62+ fdlist = []
63+ select_args = None
64+ select_handlers = None
65+ #
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 ):
73+ raise ValueError , \
74+ '(fd, mode) combination already registered'
75+ fdlist .append ((fd , mode , handler ))
76+ make_select_args ()
77+ #
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
81+ args = (fd ,) + args
82+ n = len (args )
83+ for i in range (len (fdlist )):
84+ if fdlist [i ][:n ] == args :
85+ del fdlist [i ]
86+ make_select_args ()
87+ #
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 :
93+ if mode == 'r' :
94+ rlist .append (fd )
95+ rhandlers [`fd` ] = handler
96+ if mode == 'w' :
97+ wlist .append (fd )
98+ whandlers [`fd` ] = handler
99+ if mode == 'x' :
100+ xlist .append (fd )
101+ xhandlers [`fd` ] = handler
102+ if rlist or wlist or xlist :
103+ select_args = rlist , wlist , xlist
104+ select_handlers = rhandlers , whandlers , xhandlers
105+ else :
106+ select_args = None
107+ select_handlers = None
108+ #
109+ def do_select ():
110+ import select
111+ reply = apply (select .select , select_args )
112+ for mode in 0 , 1 , 2 :
113+ list = reply [mode ]
114+ for fd in list :
115+ handler = select_handlers [mode ][`fd` ]
116+ handler (fd , 'rwx' [mode ])
117+
118+
52119# Event processing main loop.
53120# Return when there are no windows left, or when an unhandled
54121# exception occurs. (It is safe to restart the main loop after
@@ -57,17 +124,111 @@ def anywindow():
57124# into KeyboardInterrupt exceptions; these are turned back in events.
58125#
59126def mainloop ():
60- while windows :
127+ stdwin_select_handler () # Process events already in stdwin queue
128+ fd = stdwin .fileno ()
129+ while 1 :
130+ if windows :
131+ registerfd (fd , 'r' , stdwin_select_handler )
132+ try :
133+ while windows :
134+ do_select ()
135+ stdwin_select_handler ()
136+ finally :
137+ unregisterfd (fd )
138+ elif fdlist :
139+ while fdlist and not windows :
140+ do_select ()
141+ else :
142+ break
143+
144+
145+ # Handle stdwin events until none are left
146+ #
147+ def stdwin_select_handler (* args ):
148+ while 1 :
149+ try :
150+ event = stdwinq .pollevent ()
151+ except KeyboardInterrupt :
152+ event = (WE_COMMAND , None , WC_CANCEL )
153+ if event is None :
154+ break
155+ dispatch (event )
156+
157+
158+ # Run a modal dialog loop for a window. The dialog window must have
159+ # been registered first. This prohibits most events (except size/draw
160+ # events) to other windows. The modal dialog loop ends when the
161+ # dialog window unregisters itself.
162+ #
163+ passthrough = WE_SIZE , WE_DRAW
164+ beeping = WE_MOUSE_DOWN , WE_COMMAND , WE_CHAR , WE_KEY , WE_CLOSE , WE_MENU
165+ #
166+ def modaldialog (window ):
167+ if window not in windows :
168+ raise ValueError , 'modaldialog window not registered'
169+ while window in windows :
61170 try :
62- dispatch ( stdwinq .getevent () )
171+ event = stdwinq .getevent ()
63172 except KeyboardInterrupt :
64- dispatch (WE_COMMAND , stdwin .getactive (), WC_CANCEL )
173+ event = WE_COMMAND , None , WC_CANCEL
174+ etype , ewindow , edetail = event
175+ if etype not in passthrough and ewindow <> window :
176+ if etype in beeping :
177+ stdwin .fleep ()
178+ continue
179+ dispatch (event )
65180
66181
67182# Dispatch a single event.
183+ # Events for the no window in particular are sent to the active window
184+ # or to the last window that received an event (these hacks are for the
185+ # WE_LOST_SEL event, which is directed to no particular window).
68186# Windows not in the windows list don't get their events:
69187# events for such windows are silently ignored.
70188#
71189def dispatch (event ):
72- if event [1 ] in windows :
73- event [1 ].dispatch (event )
190+ global last_window
191+ if event [1 ] == None :
192+ active = stdwin .getactive ()
193+ if active : last_window = active
194+ else :
195+ last_window = event [1 ]
196+ if last_window in windows :
197+ last_window .dispatch (event )
198+
199+
200+ # Dialog base class
201+ #
202+ class Dialog :
203+ #
204+ def init (self , title ):
205+ self .window = stdwin .open (title )
206+ self .window .dispatch = self .dispatch
207+ register (self .window )
208+ return self
209+ #
210+ def close (self ):
211+ unregister (self .window )
212+ del self .window .dispatch
213+ self .window .close ()
214+ #
215+ def dispatch (self , event ):
216+ etype , ewindow , edetail = event
217+ if etype == WE_CLOSE :
218+ self .close ()
219+
220+
221+ # Standard modal dialogs
222+ # XXX implemented using stdwin dialogs for now
223+ #
224+ def askstr (prompt , default ):
225+ return stdwin .askstr (prompt , default )
226+ #
227+ def askync (prompt , yesorno ):
228+ return stdwin .askync (prompt , yesorno )
229+ #
230+ def askfile (prompt , default , new ):
231+ return stdwin .askfile (prompt , default , new )
232+ #
233+ def message (msg ):
234+ stdwin .message (msg )
0 commit comments