* mainloop.py: added facility for calling select(). Also added

embryonic facility for pseudo-modal dialogs.
* stdwinevents.py: added modifier masks for key/mouse events
* renamed exceptions in nntplib.py
* Changed string.join() to call string.joinfields() to profit of
  strop.joinfields()
This commit is contained in:
Guido van Rossum 1992-11-26 09:17:19 +00:00
parent c89705d697
commit 18fc5696c8
7 changed files with 374 additions and 28 deletions

View File

@ -13,6 +13,11 @@ from stdwinevents import *
windows = []
# Last window that ever received an event
#
last_window = None
# Function to register a window.
#
def register(win):
@ -28,6 +33,9 @@ def register(win):
# (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:
@ -49,6 +57,65 @@ def anywindow():
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
@ -57,17 +124,111 @@ def anywindow():
# into KeyboardInterrupt exceptions; these are turned back in events.
#
def mainloop():
while windows:
stdwin_select_handler() # Process events already in stdwin queue
fd = stdwin.fileno()
while 1:
if windows:
registerfd(fd, 'r', stdwin_select_handler)
try:
while windows:
do_select()
stdwin_select_handler()
finally:
unregisterfd(fd)
elif fdlist:
while fdlist and not windows:
do_select()
else:
break
# Handle stdwin events until none are left
#
def stdwin_select_handler(*args):
while 1:
try:
dispatch(stdwinq.getevent())
event = stdwinq.pollevent()
except KeyboardInterrupt:
dispatch(WE_COMMAND, stdwin.getactive(), WC_CANCEL)
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):
if event[1] in windows:
event[1].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)
return self
#
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)

View File

@ -44,3 +44,18 @@ WC_RETURN = 9 # return or enter key
WS_CLIPBOARD = 0
WS_PRIMARY = 1
WS_SECONDARY = 2
# Modifier masks in key and mouse events
WM_SHIFT = (1 << 0)
WM_LOCK = (1 << 1)
WM_CONTROL = (1 << 2)
WM_META = (1 << 3)
WM_OPTION = (1 << 4)
WM_NUM = (1 << 5)
WM_BUTTON1 = (1 << 8)
WM_BUTTON2 = (1 << 9)
WM_BUTTON3 = (1 << 10)
WM_BUTTON4 = (1 << 11)
WM_BUTTON5 = (1 << 12)

View File

@ -4,7 +4,7 @@
# Example:
#
# >>> from nntp import NNTP
# >>> from nntplib import NNTP
# >>> s = NNTP().init('charon')
# >>> resp, count, first, last, name = s.group('nlnet.misc')
# >>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
@ -32,12 +32,12 @@ import socket
import string
# Exception raiseds when an error or invalid response is received
# Exception raised when an error or invalid response is received
error_reply = 'nntp.error_reply' # unexpected [123]xx reply
error_function = 'nntp.error_function' # 4xx errors
error_form = 'nntp.error_form' # 5xx errors
error_protocol = 'nntp.error_protocol' # response does not begin with [1-5]
error_reply = 'nntplib.error_reply' # unexpected [123]xx reply
error_temp = 'nntplib.error_temp' # 4xx errors
error_perm = 'nntplib.error_perm' # 5xx errors
error_proto = 'nntplib.error_proto' # response does not begin with [1-5]
# Standard port used by NNTP servers
@ -119,11 +119,11 @@ class NNTP:
if self.debugging: print '*resp*', `resp`
c = resp[:1]
if c == '4':
raise error_function, resp
raise error_temp, resp
if c == '5':
raise error_form, resp
raise error_perm, resp
if c not in '123':
raise error_protocol, resp
raise error_proto, resp
return resp
# Internal: get a response plus following text from the server.
@ -342,7 +342,7 @@ class NNTP:
def ihave(self, id, f):
resp = self.shortcmd('IHAVE ' + id)
# Raises error_function if the server already has it
# Raises error_??? if the server already has it
if resp[0] <> '3':
raise error_reply, resp
while 1:

View File

@ -13,6 +13,11 @@ from stdwinevents import *
windows = []
# Last window that ever received an event
#
last_window = None
# Function to register a window.
#
def register(win):
@ -28,6 +33,9 @@ def register(win):
# (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:
@ -49,6 +57,65 @@ def anywindow():
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
@ -57,17 +124,111 @@ def anywindow():
# into KeyboardInterrupt exceptions; these are turned back in events.
#
def mainloop():
while windows:
stdwin_select_handler() # Process events already in stdwin queue
fd = stdwin.fileno()
while 1:
if windows:
registerfd(fd, 'r', stdwin_select_handler)
try:
while windows:
do_select()
stdwin_select_handler()
finally:
unregisterfd(fd)
elif fdlist:
while fdlist and not windows:
do_select()
else:
break
# Handle stdwin events until none are left
#
def stdwin_select_handler(*args):
while 1:
try:
dispatch(stdwinq.getevent())
event = stdwinq.pollevent()
except KeyboardInterrupt:
dispatch(WE_COMMAND, stdwin.getactive(), WC_CANCEL)
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):
if event[1] in windows:
event[1].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)
return self
#
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)

View File

@ -44,3 +44,18 @@ WC_RETURN = 9 # return or enter key
WS_CLIPBOARD = 0
WS_PRIMARY = 1
WS_SECONDARY = 2
# Modifier masks in key and mouse events
WM_SHIFT = (1 << 0)
WM_LOCK = (1 << 1)
WM_CONTROL = (1 << 2)
WM_META = (1 << 3)
WM_OPTION = (1 << 4)
WM_NUM = (1 << 5)
WM_BUTTON1 = (1 << 8)
WM_BUTTON2 = (1 << 9)
WM_BUTTON3 = (1 << 10)
WM_BUTTON4 = (1 << 11)
WM_BUTTON5 = (1 << 12)

View File

@ -82,10 +82,7 @@ def splitfields(s, sep):
# Join words with spaces between them
def join(words):
res = ''
for w in words:
res = res + (' ' + w)
return res[1:]
return joinfields(words, ' ')
# Join fields with separator
def joinfields(words, sep):

View File

@ -82,10 +82,7 @@ def splitfields(s, sep):
# Join words with spaces between them
def join(words):
res = ''
for w in words:
res = res + (' ' + w)
return res[1:]
return joinfields(words, ' ')
# Join fields with separator
def joinfields(words, sep):