blob: f1fe6170b12fdf27a6df71522662e083ef055289 [file] [log] [blame]
Guido van Rossum7045dd01991-08-16 13:28:28 +00001# 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
5
6
7import stdwin, stdwinq
8from stdwinevents import *
9
10
11# List of windows known to the main loop.
12#
13windows = []
14
15
Guido van Rossum18fc5691992-11-26 09:17:19 +000016# Last window that ever received an event
17#
18last_window = None
19
20
Guido van Rossum7045dd01991-08-16 13:28:28 +000021# Function to register a window.
22#
23def register(win):
24 # First test the dispatch function by passing it a null event --
25 # this catches registration of unconforming windows.
Guido van Rossum89a78691992-12-14 12:57:56 +000026 win.dispatch((WE_NULL, win, None))
Guido van Rossum7045dd01991-08-16 13:28:28 +000027 if win not in windows:
28 windows.append(win)
29
30
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).
34#
35def unregister(win):
Guido van Rossum18fc5691992-11-26 09:17:19 +000036 global last_window
37 if win == last_window:
38 last_window = None
Guido van Rossum7045dd01991-08-16 13:28:28 +000039 if win in windows:
40 windows.remove(win) # Not in 0.9.1
Guido van Rossum3f4f9171991-11-19 20:41:07 +000041 # 0.9.1 solution:
42 #for i in range(len(windows)):
43 # if windows[i] = win:
44 # del windows[i]
45 # break
Guido van Rossum7045dd01991-08-16 13:28:28 +000046
47
48# Interfaces used by WindowSched.
49#
50def countwindows():
51 return len(windows)
52#
53def anywindow():
54 if windows:
55 return windows[0]
56 else:
57 return None
58
59
Guido van Rossum18fc5691992-11-26 09:17:19 +000060# NEW: register any number of file descriptors
61#
62fdlist = []
63select_args = None
64select_handlers = None
65#
66def 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#
78def 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#
88def 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#
109def 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
Guido van Rossum7045dd01991-08-16 13:28:28 +0000119# 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.
125#
126def mainloop():
Guido van Rossum18fc5691992-11-26 09:17:19 +0000127 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#
147def stdwin_select_handler(*args):
148 while 1:
Guido van Rossum7045dd01991-08-16 13:28:28 +0000149 try:
Guido van Rossum18fc5691992-11-26 09:17:19 +0000150 event = stdwinq.pollevent()
Guido van Rossum7045dd01991-08-16 13:28:28 +0000151 except KeyboardInterrupt:
Guido van Rossum18fc5691992-11-26 09:17:19 +0000152 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#
163passthrough = WE_SIZE, WE_DRAW
164beeping = WE_MOUSE_DOWN, WE_COMMAND, WE_CHAR, WE_KEY, WE_CLOSE, WE_MENU
165#
166def modaldialog(window):
167 if window not in windows:
168 raise ValueError, 'modaldialog window not registered'
169 while window in windows:
170 try:
171 event = stdwinq.getevent()
172 except KeyboardInterrupt:
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)
Guido van Rossum7045dd01991-08-16 13:28:28 +0000180
181
182# Dispatch a single event.
Guido van Rossum18fc5691992-11-26 09:17:19 +0000183# 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).
Guido van Rossum7045dd01991-08-16 13:28:28 +0000186# Windows not in the windows list don't get their events:
187# events for such windows are silently ignored.
188#
189def dispatch(event):
Guido van Rossum18fc5691992-11-26 09:17:19 +0000190 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#
202class 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#
224def askstr(prompt, default):
225 return stdwin.askstr(prompt, default)
226#
227def askync(prompt, yesorno):
228 return stdwin.askync(prompt, yesorno)
229#
230def askfile(prompt, default, new):
231 return stdwin.askfile(prompt, default, new)
232#
233def message(msg):
234 stdwin.message(msg)