]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
* mainloop.py: added facility for calling select(). Also added
authorGuido van Rossum <guido@python.org>
Thu, 26 Nov 1992 09:17:19 +0000 (09:17 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 26 Nov 1992 09:17:19 +0000 (09:17 +0000)
  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()

Lib/lib-stdwin/mainloop.py
Lib/lib-stdwin/stdwinevents.py
Lib/nntplib.py
Lib/stdwin/mainloop.py
Lib/stdwin/stdwinevents.py
Lib/string.py
Lib/stringold.py

index 0cf5bde6611c2f903e9ad34f8ec7277d1a394eda..ab8ad3a014cc7a940666351b09299b119806c760 100644 (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:
+                       event = stdwinq.pollevent()
+               except KeyboardInterrupt:
+                       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:
-                       dispatch(stdwinq.getevent())
+                       event = stdwinq.getevent()
                except KeyboardInterrupt:
-                       dispatch(WE_COMMAND, stdwin.getactive(), WC_CANCEL)
+                       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)
index 9f22dd9aa13b9d94e92abf26b932d4702bd66d39..62cf8d2931bb00e6c434589d221aecf5c643162e 100644 (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)
index 18fa398c4fcfa9028d0320adf8c777f8eda98fa8..c448d48241b2a74a179709f05f849e08d12c0bf1 100644 (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:
index 0cf5bde6611c2f903e9ad34f8ec7277d1a394eda..ab8ad3a014cc7a940666351b09299b119806c760 100755 (executable)
@@ -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:
+                       event = stdwinq.pollevent()
+               except KeyboardInterrupt:
+                       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:
-                       dispatch(stdwinq.getevent())
+                       event = stdwinq.getevent()
                except KeyboardInterrupt:
-                       dispatch(WE_COMMAND, stdwin.getactive(), WC_CANCEL)
+                       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)
index 9f22dd9aa13b9d94e92abf26b932d4702bd66d39..62cf8d2931bb00e6c434589d221aecf5c643162e 100755 (executable)
@@ -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)
index b4e0d5e7661f1edffdbf0bc250602714ade5a0c8..aed3eafb544ecb6a1b963541b41d1b08e8cb251e 100644 (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):
index b4e0d5e7661f1edffdbf0bc250602714ade5a0c8..aed3eafb544ecb6a1b963541b41d1b08e8cb251e 100644 (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):