(py-indent-right, py-outdent-left): new commands, bound to C-c C-r and
[python/dscho.git] / Lib / stdwin / mainloop.py
blobaa40c34b4ec508fa48a25b3ada1f7b9d4f20c8e0
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
7 import stdwin, stdwinq
8 from stdwinevents import *
11 # List of windows known to the main loop.
13 windows = []
16 # Last window that ever received an event
18 last_window = None
21 # Function to register a window.
23 def register(win):
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:
28 windows.append(win)
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).
35 def unregister(win):
36 global last_window
37 if win == last_window:
38 last_window = None
39 if win in windows:
40 windows.remove(win) # Not in 0.9.1
41 # 0.9.1 solution:
42 #for i in range(len(windows)):
43 # if windows[i] = win:
44 # del windows[i]
45 # break
48 # Interfaces used by WindowSched.
50 def countwindows():
51 return len(windows)
53 def anywindow():
54 if windows:
55 return windows[0]
56 else:
57 return None
60 # NEW: register any number of file descriptors
62 fdlist = []
63 select_args = None
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):
73 raise ValueError, \
74 '(fd, mode) combination already registered'
75 fdlist.append((fd, mode, handler))
76 make_select_args()
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()
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
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])
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
127 def mainloop():
128 global recursion_level
129 recursion_level = recursion_level + 1
130 try:
131 stdwin_select_handler() # Process events already in queue
132 while 1:
133 if windows and not fdlist:
134 while windows and not fdlist:
135 try:
136 event = stdwinq.getevent()
137 except KeyboardInterrupt:
138 event = (WE_COMMAND, \
139 None, WC_CANCEL)
140 dispatch(event)
141 elif windows and fdlist:
142 fd = stdwin.fileno()
143 if recursion_level == 1:
144 registerfd(fd, 'r', stdwin_select_handler)
145 try:
146 while windows:
147 do_select()
148 stdwin_select_handler()
149 finally:
150 if recursion_level == 1:
151 unregisterfd(fd)
152 elif fdlist:
153 while fdlist and not windows:
154 do_select()
155 else:
156 break
157 finally:
158 recursion_level = recursion_level - 1
161 # Check for events without ever blocking
163 def check():
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):
171 while 1:
172 try:
173 event = stdwinq.pollevent()
174 except KeyboardInterrupt:
175 event = (WE_COMMAND, None, WC_CANCEL)
176 if event is None:
177 break
178 dispatch(event)
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:
193 try:
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:
199 if etype in beeping:
200 stdwin.fleep()
201 continue
202 dispatch(event)
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.
212 def dispatch(event):
213 global last_window
214 if event[1] == None:
215 active = stdwin.getactive()
216 if active: last_window = active
217 else:
218 last_window = event[1]
219 if last_window in windows:
220 last_window.dispatch(event)
223 # Dialog base class
225 class Dialog:
227 def __init__(self, title):
228 self.window = stdwin.open(title)
229 self.window.dispatch = self.dispatch
230 register(self.window)
232 def close(self):
233 unregister(self.window)
234 del self.window.dispatch
235 self.window.close()
237 def dispatch(self, event):
238 etype, ewindow, edetail = event
239 if etype == WE_CLOSE:
240 self.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)
255 def message(msg):
256 stdwin.message(msg)