|
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 self.ae_handlers.has_key((_class, _type)): |
|
140 _function = self.ae_handlers[(_class, _type)] |
|
141 elif self.ae_handlers.has_key((_class, '****')): |
|
142 _function = self.ae_handlers[(_class, '****')] |
|
143 elif self.ae_handlers.has_key(('****', '****')): |
|
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 _parameters.has_key('----'): |
|
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() |