Home | History | Annotate | Download | only in plat-mac
      1 """MiniAEFrame - A minimal AppleEvent Application framework.
      2 
      3 There are two classes:
      4     AEServer -- a mixin class offering nice AE handling.
      5     MiniApplication -- a very minimal alternative to FrameWork.py,
      6         only suitable for the simplest of AppleEvent servers.
      7 """
      8 
      9 from warnings import warnpy3k
     10 warnpy3k("In 3.x, the MiniAEFrame module is removed.", stacklevel=2)
     11 
     12 import traceback
     13 import MacOS
     14 from Carbon import AE
     15 from Carbon.AppleEvents import *
     16 from Carbon import Evt
     17 from Carbon.Events import *
     18 from Carbon import Menu
     19 from Carbon import Win
     20 from Carbon.Windows import *
     21 from Carbon import Qd
     22 
     23 import aetools
     24 import EasyDialogs
     25 
     26 kHighLevelEvent = 23                # Not defined anywhere for Python yet?
     27 
     28 
     29 class MiniApplication:
     30 
     31     """A minimal FrameWork.Application-like class"""
     32 
     33     def __init__(self):
     34         self.quitting = 0
     35         # Initialize menu
     36         self.appleid = 1
     37         self.quitid = 2
     38         Menu.ClearMenuBar()
     39         self.applemenu = applemenu = Menu.NewMenu(self.appleid, "\024")
     40         applemenu.AppendMenu("%s;(-" % self.getaboutmenutext())
     41         if MacOS.runtimemodel == 'ppc':
     42             applemenu.AppendResMenu('DRVR')
     43         applemenu.InsertMenu(0)
     44         self.quitmenu = Menu.NewMenu(self.quitid, "File")
     45         self.quitmenu.AppendMenu("Quit")
     46         self.quitmenu.SetItemCmd(1, ord("Q"))
     47         self.quitmenu.InsertMenu(0)
     48         Menu.DrawMenuBar()
     49 
     50     def __del__(self):
     51         self.close()
     52 
     53     def close(self):
     54         pass
     55 
     56     def mainloop(self, mask = everyEvent, timeout = 60*60):
     57         while not self.quitting:
     58             self.dooneevent(mask, timeout)
     59 
     60     def _quit(self):
     61         self.quitting = 1
     62 
     63     def dooneevent(self, mask = everyEvent, timeout = 60*60):
     64         got, event = Evt.WaitNextEvent(mask, timeout)
     65         if got:
     66             self.lowlevelhandler(event)
     67 
     68     def lowlevelhandler(self, event):
     69         what, message, when, where, modifiers = event
     70         h, v = where
     71         if what == kHighLevelEvent:
     72             msg = "High Level Event: %r %r" % (code(message), code(h | (v<<16)))
     73             try:
     74                 AE.AEProcessAppleEvent(event)
     75             except AE.Error, err:
     76                 print 'AE error: ', err
     77                 print 'in', msg
     78                 traceback.print_exc()
     79             return
     80         elif what == keyDown:
     81             c = chr(message & charCodeMask)
     82             if modifiers & cmdKey:
     83                 if c == '.':
     84                     raise KeyboardInterrupt, "Command-period"
     85                 if c == 'q':
     86                     if hasattr(MacOS, 'OutputSeen'):
     87                         MacOS.OutputSeen()
     88                     self.quitting = 1
     89                     return
     90         elif what == mouseDown:
     91             partcode, window = Win.FindWindow(where)
     92             if partcode == inMenuBar:
     93                 result = Menu.MenuSelect(where)
     94                 id = (result>>16) & 0xffff      # Hi word
     95                 item = result & 0xffff      # Lo word
     96                 if id == self.appleid:
     97                     if item == 1:
     98                         EasyDialogs.Message(self.getabouttext())
     99                     elif item > 1 and hasattr(Menu, 'OpenDeskAcc'):
    100                         name = self.applemenu.GetMenuItemText(item)
    101                         Menu.OpenDeskAcc(name)
    102                 elif id == self.quitid and item == 1:
    103                     if hasattr(MacOS, 'OutputSeen'):
    104                         MacOS.OutputSeen()
    105                     self.quitting = 1
    106                 Menu.HiliteMenu(0)
    107                 return
    108         # Anything not handled is passed to Python/SIOUX
    109         if hasattr(MacOS, 'HandleEvent'):
    110             MacOS.HandleEvent(event)
    111         else:
    112             print "Unhandled event:", event
    113 
    114     def getabouttext(self):
    115         return self.__class__.__name__
    116 
    117     def getaboutmenutext(self):
    118         return "About %s\311" % self.__class__.__name__
    119 
    120 
    121 class AEServer:
    122 
    123     def __init__(self):
    124         self.ae_handlers = {}
    125 
    126     def installaehandler(self, classe, type, callback):
    127         AE.AEInstallEventHandler(classe, type, self.callback_wrapper)
    128         self.ae_handlers[(classe, type)] = callback
    129 
    130     def close(self):
    131         for classe, type in self.ae_handlers.keys():
    132             AE.AERemoveEventHandler(classe, type)
    133 
    134     def callback_wrapper(self, _request, _reply):
    135         _parameters, _attributes = aetools.unpackevent(_request)
    136         _class = _attributes['evcl'].type
    137         _type = _attributes['evid'].type
    138 
    139         if (_class, _type) in self.ae_handlers:
    140             _function = self.ae_handlers[(_class, _type)]
    141         elif (_class, '****') in self.ae_handlers:
    142             _function = self.ae_handlers[(_class, '****')]
    143         elif ('****', '****') in self.ae_handlers:
    144             _function = self.ae_handlers[('****', '****')]
    145         else:
    146             raise 'Cannot happen: AE callback without handler', (_class, _type)
    147 
    148         # XXXX Do key-to-name mapping here
    149 
    150         _parameters['_attributes'] = _attributes
    151         _parameters['_class'] = _class
    152         _parameters['_type'] = _type
    153         if '----' in _parameters:
    154             _object = _parameters['----']
    155             del _parameters['----']
    156             # The try/except that used to be here can mask programmer errors.
    157             # Let the program crash, the programmer can always add a **args
    158             # to the formal parameter list.
    159             rv = _function(_object, **_parameters)
    160         else:
    161             #Same try/except comment as above
    162             rv = _function(**_parameters)
    163 
    164         if rv is None:
    165             aetools.packevent(_reply, {})
    166         else:
    167             aetools.packevent(_reply, {'----':rv})
    168 
    169 
    170 def code(x):
    171     "Convert a long int to the 4-character code it really is"
    172     s = ''
    173     for i in range(4):
    174         x, c = divmod(x, 256)
    175         s = chr(c) + s
    176     return s
    177 
    178 class _Test(AEServer, MiniApplication):
    179     """Mini test application, handles required events"""
    180 
    181     def __init__(self):
    182         MiniApplication.__init__(self)
    183         AEServer.__init__(self)
    184         self.installaehandler('aevt', 'oapp', self.open_app)
    185         self.installaehandler('aevt', 'quit', self.quit)
    186         self.installaehandler('****', '****', self.other)
    187         self.mainloop()
    188 
    189     def quit(self, **args):
    190         self._quit()
    191 
    192     def open_app(self, **args):
    193         pass
    194 
    195     def other(self, _object=None, _class=None, _type=None, **args):
    196         print 'AppleEvent', (_class, _type), 'for', _object, 'Other args:', args
    197 
    198 
    199 if __name__ == '__main__':
    200     _Test()
    201