home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fnb101.zip / Lib / site-packages / Fnorb / orb / TkReactor.py < prev    next >
Text File  |  1999-06-28  |  8KB  |  287 lines

  1. #!/usr/bin/env python
  2. #############################################################################
  3. # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999
  4. # All Rights Reserved.
  5. #
  6. # The software contained on this media is the property of the DSTC Pty
  7. # Ltd.  Use of this software is strictly in accordance with the
  8. # license agreement in the accompanying LICENSE.HTML file.  If your
  9. # distribution of this software does not contain a LICENSE.HTML file
  10. # then you have no rights to use this software in any manner and
  11. # should contact DSTC at the address below to determine an appropriate
  12. # licensing arrangement.
  13. #      DSTC Pty Ltd
  14. #      Level 7, GP South
  15. #      Staff House Road
  16. #      University of Queensland
  17. #      St Lucia, 4072
  18. #      Australia
  19. #      Tel: +61 7 3365 4310
  20. #      Fax: +61 7 3365 4311
  21. #      Email: enquiries@dstc.edu.au
  22. # This software is being provided "AS IS" without warranty of any
  23. # kind.  In no event shall DSTC Pty Ltd be liable for damage of any
  24. # kind arising out of or in connection with the use or performance of
  25. # this software.
  26. #
  27. # Project:      Fnorb
  28. # File:         $Source: /units/arch/src/Fnorb/orb/RCS/TkReactor.py,v $
  29. # Version:      @(#)$RCSfile: TkReactor.py,v $ $Revision: 1.15 $
  30. #
  31. #############################################################################
  32. """ A Reactor for use with 'tkinter'. 
  33.  
  34. 'tkinter' (and 'Tk' itself) are NOT thread-safe, and therefore this module
  35. assumes a single-threaded environment.
  36.  
  37. """
  38.  
  39.  
  40. # The Python module for Tk 4.1 and upwards is "_tkinter", for Tk 4.0 it is
  41. # "tkinter" 8^(
  42. try:
  43.     import _tkinter
  44.  
  45. except ImportError:
  46.     import tkinter; _tkinter = tkinter
  47.     
  48. # Fnorb modules.
  49. import Reactor
  50.  
  51.  
  52. def TkReactor_init():
  53.     """ Initialise the TkReactor.
  54.  
  55.     There can only be one instance of any concrete reactor class per process.
  56.  
  57.     """
  58.     try:
  59.     reactor = TkReactor()
  60.  
  61.     except Reactor.Reactor, reactor:
  62.     pass
  63.  
  64.     return reactor
  65.  
  66.  
  67. class TkReactor(Reactor.Reactor):
  68.     """ The TkReactor.
  69.  
  70.     The TkReactor uses the Tk event loop to dispatch Fnorb events.
  71.  
  72.     """
  73.  
  74.     def __init__(self):
  75.     """ Constructor. """
  76.  
  77.     # There can be at most one instance of any concrete reactor class per
  78.     # process.
  79.     if Reactor.Reactor._instance is not None:
  80.         # A reactor already exists.
  81.         raise Reactor.Reactor._instance
  82.  
  83.     Reactor.Reactor._instance = self
  84.  
  85.     # A dictionary of all registered event handlers. All handles in the
  86.     # TkReactor are actually just file descriptors.
  87.     self.__handlers = {} # {Handle: (EventHandler, Mask)}
  88.  
  89.     return
  90.  
  91.     #########################################################################
  92.     # Reactor interface.
  93.     #########################################################################
  94.  
  95.     def register_handler(self, handler, mask):
  96.     """ Register an event handler. """
  97.  
  98.     # Get the event handler's underlying I/O handle.
  99.     handle = handler.handle()
  100.  
  101.     # If the handler is already registered then update the mask.
  102.     try:
  103.         # Find the event handler associated with the handle.
  104.         (handler, handler_mask) = self.__handlers[handle]
  105.  
  106.         # Update the mask.
  107.         handler_mask = handler_mask | mask
  108.  
  109.     # Otherwise, add the new handler.
  110.     except KeyError:
  111.         handler_mask = mask
  112.  
  113.     # Do the add/update.
  114.     self.__handlers[handle] = (handler, handler_mask)
  115.  
  116.     # Register with Tk.
  117.     self.__register_Tk_handler(handle, handler_mask)
  118.  
  119.     return
  120.  
  121.     def unregister_handler(self, handler, mask):
  122.     """ Withdraw a handler's registration. """
  123.  
  124.     # Get the event handler's underlying I/O handle.
  125.     handle = handler.handle()
  126.  
  127.     try:
  128.         # Find the event handler associated with the handle.
  129.         (handler, handler_mask) = self.__handlers[handle]
  130.  
  131.         # Update the mask.
  132.         handler_mask = handler_mask & ~mask
  133.  
  134.         # If the mask is now zero (ie. the handler is no longer interested
  135.         # in *any* events) then delete the handler.
  136.         if handler_mask == 0:
  137.         # Remove the handler from Tk.
  138.         _tkinter.deletefilehandler(handle)
  139.  
  140.         # Delete it!
  141.         del self.__handlers[handle]
  142.  
  143.         # Otherwise, update the handler's mask and re-register with Tk.
  144.         else:
  145.         # Update the handler's mask.
  146.         self.__handlers[handle] = (handler, handler_mask)
  147.  
  148.         # Re-register with Tk.
  149.         self.__register_Tk_handler(handle, handler_mask)
  150.  
  151.     # Ignore any attempts to un-register something that wasn't registerd!
  152.     except KeyError:
  153.         pass
  154.  
  155.     return
  156.  
  157.     def start_event_loop(self, timeout=None):
  158.     """ Start the event loop. """
  159.  
  160.     # Enter the Tk mainloop (ie. Tk will dispatch the events).
  161.     _tkinter.mainloop()
  162.  
  163.     # Close all registered handlers.
  164.     self.__close_all_handlers()
  165.  
  166.     return
  167.  
  168.     def stop_event_loop(self):
  169.     """ Stop the event loop. """
  170.  
  171.     # Quit the Tk mainloop.
  172.     _tkinter.quit()
  173.  
  174.     return
  175.  
  176.     def do_one_event(self):
  177.     """ Dispatch a single event. """
  178.  
  179.     _tkinter.dooneevent()
  180.  
  181.     return
  182.  
  183.     # The following two methods are provided to allow Fnorb events to be
  184.     # handled in other event loops.
  185.     def handles(self):
  186.     """ Return the read/write/exception handles for registered handlers.
  187.  
  188.     The return value is a tuple in the form:-
  189.  
  190.     ([ReadHandles], [WriteHandles], [ExceptionHandles])
  191.  
  192.     """
  193.     return self.__get_handles()
  194.  
  195.     def handle_one_event(self, handle, tk_mask):
  196.     """ Handle a single Tk event. """
  197.  
  198.     self.__handle_Tk_event(handle, tk_mask)
  199.  
  200.     return
  201.  
  202.     #########################################################################
  203.     # Private interface.
  204.     #########################################################################
  205.  
  206.     def __get_handles(self):
  207.     """ Return the read/write/exception handles for registered handlers.
  208.  
  209.     The return value is a tuple in the form:-
  210.  
  211.     ([ReadHandles], [WriteHandles], [ExceptionHandles])
  212.  
  213.     """
  214.     iwtd = {}
  215.     owtd = {}
  216.     ewtd = {}
  217.  
  218.     for handle in self.__handlers.keys():
  219.         # Find the event handler associated with the handle.
  220.         (handler, mask) = self.__handlers[handle]
  221.  
  222.         if mask & Reactor.READ:
  223.         iwtd[handle] = None
  224.  
  225.         if mask & Reactor.WRITE:
  226.         owtd[handle] = None
  227.  
  228.         # Listen for errors on all handles.
  229.         ewtd[handle] = None
  230.  
  231.     return (iwtd.keys(), owtd.keys(), ewtd.keys())
  232.  
  233.     def __handle_Tk_event(self, handle, tk_mask):
  234.     """ Handle an event. """
  235.  
  236.     # Translate between Tk and Fnorb event masks.
  237.     mask = 0x0
  238.     if tk_mask & _tkinter.READABLE:
  239.         mask = mask | Reactor.READ
  240.  
  241.     if tk_mask & _tkinter.WRITABLE:
  242.         mask = mask | Reactor.WRITE
  243.  
  244.     if tk_mask & _tkinter.EXCEPTION:
  245.         mask = mask | Reactor.EXCEPTION
  246.  
  247.     # Find the event handler associated with the handle.
  248.     (handler, handler_mask) = self.__handlers[handle]
  249.  
  250.     # Handler callback.
  251.     handler.handle_event(mask)
  252.     
  253.     return
  254.  
  255.     def __register_Tk_handler(self, handle, mask):
  256.     """ Register a file handler with Tk. """
  257.  
  258.     # Translate between Fnorb and Tk event masks (we are always interested
  259.     # in exceptions!).
  260.     tk_mask = _tkinter.EXCEPTION
  261.  
  262.     if mask & Reactor.READ:
  263.         tk_mask = tk_mask | _tkinter.READABLE
  264.  
  265.     if mask & Reactor.WRITE:
  266.         tk_mask = tk_mask | _tkinter.WRITABLE
  267.  
  268.     # Register with Tk.
  269.     _tkinter.createfilehandler(handle, tk_mask, self.__handle_Tk_event)
  270.     
  271.     return
  272.  
  273.     def __close_all_handlers(self):
  274.     """ Close all registered handlers. """
  275.  
  276.     # We work on a copy of the list, 'cos the handlers will most likely
  277.     # call 'unregister_handler' in their 'close' method.
  278.     for (handler, mask) in self.__handlers.values():
  279.         # Handler callback.
  280.         handler.handle_close()
  281.  
  282.     return
  283.  
  284. #############################################################################
  285.